Compare commits

...

40 Commits

Author SHA1 Message Date
Denny Sheirer
a24c3736f4 #1340 Updates tuner and frequency controllers to apply locking to ensure multi-threaded access to freuqency control planes doesn't allow center tuned frequency to become indeterminant which can result in channels being mistuned and stop decoding. (#1341)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-11-20 07:55:30 -05:00
Denny Sheirer
ac61b681e6 #1338 Updates logger to include date in log entries. Removes info logger when creating channel log files. (#1339)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-11-20 05:54:05 -05:00
Denny Sheirer
0866bfd555 #1336 Resolves issue with color setting changes not inheriting the correct translucency which causes the channel overlays in the spectral display to be solid color instead of semi-transparent. (#1337)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-11-20 05:43:28 -05:00
Denny Sheirer
79fed701d9 #1337 Updates build to use JDK19 for distribution images and updates all 3rd-party libraries to latest. Note: build system continues to be compatible with JDK 17 and 18, but Gradle 7.6 to build distribution images. Gradle 7.6 is not released yet, but RC3 is available. (#1335)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-11-20 05:36:41 -05:00
Denny Sheirer
48a93990e8 #1291 Updates DC removal processing across tuner sample streams to run on a periodic timer to reduce overall processing requirements. Updates build version to 0.5.0 beta 5 (#1292)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-07-23 08:14:31 -04:00
Denny Sheirer
414ba25d61 #1284 Resolves issue with inherent DC bias (-0.5) in RTL2832 sample conversion code. (#1285)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-07-16 08:58:09 -04:00
Shahar
f67f90e8b0 moved RecordingTuner ChannelizerType set to after the recording tuner was started. This way the sample rate is not 0. (#1279) 2022-07-11 04:34:17 -04:00
Dennis Sheirer
5751c70212 Updates to release versio 0.5.0 2022-07-11 04:21:03 -04:00
Denny Sheirer
4e15c426a8 #1253 Updates USB tuner controller to handle LibUsb bug where on resubmitting a completed transfer LibUsb tells us that the transfer is already submitted. This is happening on some Window systems. (#1263)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-05-24 04:11:26 -04:00
Denny Sheirer
ceda189260 #1179 Resolves issue with JMBE Creator running on OSX. (#1262)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-05-24 03:57:33 -04:00
Denny Sheirer
fce0ae33e7 #1181 Updates libusb osx aarch64 driver library and gradle build. (#1261)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-05-23 04:06:42 -04:00
Denny Sheirer
fc5c6ef841 #1257 restores recording tuner feature. sdrtrunk now supports multiple recording tuners. Recordings are automatically loaded/restored on application start and each recording tuner has to be manually enabled for use. (#1258)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-05-22 08:24:42 -04:00
Denny Sheirer
d0033578d5 #1181 Adds logging for mac users to install libusb if sdrtrunk can't load library. (#1251)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-05-15 07:05:53 -04:00
Dennis Sheirer
670ec3a097 Adds debug logging to USB tuner controller. 2022-05-15 06:37:25 -04:00
Denny Sheirer
8bfb1d5470 #1243 Updates USB tuner error handling to prevent stack overflow when tuner error occurs while streaming. (#1247)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-05-09 07:16:35 -04:00
Denny Sheirer
46a916a945 #1245 Updates spectral display show tuner options to allow new display without changing disabled state of primary display. (#1246)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-05-08 05:01:52 -04:00
Denny Sheirer
459e77390a #1241 Adds user preference to enable/disable audio normalization prior to MP3 encoding/recording. (#1242)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-05-07 07:11:40 -04:00
Doug Hoffman
f4ab46b79d Prefer talkgroup ID over radio ID for Calls (#1227) 2022-05-07 06:51:27 -04:00
Denny Sheirer
3c58e98788 #1239 Resolves issue where a user can't view the spectrum of a tuner when the spectral display is disabled. Tuner editor button overrides the property setting so that the view completes correctly. (#1240)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-05-07 06:36:42 -04:00
Doug Hoffman
36de81248c Don't show tuner on spectral display while disabled (#1236) 2022-05-07 06:30:11 -04:00
Dennis Sheirer
925353d515 Bump Version 0.5.0 Beta 3, Gradle 7.4.2, Embedded JDK 18.0.1 2022-05-04 14:51:27 -04:00
Denny Sheirer
7c32897321 #1229 Resolves issue with correctly identifying the port number for USB tuners that is causing some tuners not to be recognized and also generating udev errors when sdrtrunk attempts to start an already started device because it was incorrectly identified. (#1230)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-05-03 04:03:18 -04:00
Doug Hoffman
cbeda19d27 Generate audio metadata with correct to/from (#1215)
#1215 Generate audio metadata with correct to/from, preferring patch group, then talkgroup then other, for TO talkgroups.
2022-05-01 06:06:31 -04:00
Doug Hoffman
8148ca48af Normalize audio before recording (#1213)
#1213 Normalize audio before recording
2022-05-01 05:57:32 -04:00
VolFFProCoder
adcb55ffbc Add filter button to messages (#1098)
Adds filtering to channel decoded events panel.
2022-04-30 05:44:57 -04:00
Andrzej Pańkowski
1152b13220 Merge pull request #1177
* Fixes message filtering that was not being initialized.  Fixes minor spotted code issues
2022-04-30 04:25:33 -04:00
Doug Hoffman
166383e1ed Make Broadcastify Calls scheduled test configurable (#1218)
* Broadcastify Calls periodic keep-alive to avoid showing offline status
2022-04-30 04:04:10 -04:00
Denny Sheirer
0d5d1b20e3 #1223 Resolves NPE when Airspy and HackRF tuners are re-enabled after startup. Slight tweaks to TunerManager to change when discovered USB device startup takes place to potentially address intermittent fail on start for some tuners that users are seeing. Resolves issue where a started device was not unreferenced in LibUsb on shutdown. (#1224)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-04-29 08:00:18 -04:00
Denny Sheirer
77ea43f61a #1221 resolves null pointer exception in tuner editor when attempting to restart an error tuner. (#1222)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-04-28 04:40:52 -04:00
Denny Sheirer
f988344222 #1219 resolves issues with NPE and restarting an error tuner. (#1220)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-04-26 04:02:36 -04:00
Doug Hoffman
60489e1fef (icecast) Add support for inline metadata (#1212) 2022-04-25 04:38:54 -04:00
Doug Hoffman
ac8aa17a80 Check in with Broadcastify Calls to stay online while otherwise idle (#1214) 2022-04-24 05:15:34 -04:00
Denny Sheirer
25a42126df #1210 Resolves issue of tuner instances can't be garbage collected due to retained references. Updates several of the tuner controller and tuner editor classes to add/invoke dispose() methods to clear retained instance references. (#1216)
Co-authored-by: Denny Sheirer <sheirerd@ainfosec.com>
2022-04-24 04:56:10 -04:00
Denny Sheirer
1b90e0b50c #1209 updates tuner manager to properly deref usb devices on discovery. Updates tuner editors to separate enable/disable from tuner error state. Updates settings manager to disable auto-fail when loading xml file when unknown tags are encountered so that users' existing configs don't fail on startup and erase their existing settings. (#1211)
Co-authored-by: Denny Sheirer <sheirerd@ainfosec.com>
2022-04-23 06:05:12 -04:00
Denny Sheirer
7f5ad7eb20 Update README.md 2022-04-19 07:03:19 -04:00
Denny Sheirer
0e6713b6e2 Update README.md 2022-04-19 07:02:32 -04:00
Denny Sheirer
96d3996bec #1190 Tuner management redesign. Updates all tuners with direct threaded support. Incorporates USB Hotplug support. Adds black/white listing of tuners. Updates all tuner editors to have a common look and feel. Changes location of tuner configuration file and changes format to JSON. (#1208)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-04-18 07:30:58 -04:00
Denny Sheirer
0fb148d31e #1194 Resolves issue with audio stream bit rate scheduling that was causing stream disconnects for data rate under flows. (#1195)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-03-26 05:48:08 -04:00
Denny Sheirer
cebca28b19 Patch from @ImagoTrigger to implement headless operation: 9e4d2adfa9..c597d1967b (#1191)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-03-25 04:19:38 -04:00
Denny Sheirer
af8cc0255e #1186 removes error logging that indicates that a channel cannot be stopped because it doesn't exist. This happens when a second successive attempt to stop a channel fails to find the channel because the first attempt has already removed the channel from the list. (#1187)
Co-authored-by: Denny Sheirer <sheirerd@ainfosec.com>
2022-03-21 19:09:49 -04:00
330 changed files with 15219 additions and 14006 deletions

5
.idea/misc.xml generated
View File

@@ -1,7 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="liberica-17.0.2-fx" project-jdk-type="JavaSDK">
<component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="liberica-19.0.1.fx" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

View File

@@ -28,7 +28,7 @@ repositories {
maven { url "https://jitpack.io" }
}
version = '0.5.0-beta2'
version = '0.5.0-beta6'
sourceCompatibility = '17'
sourceSets {
@@ -43,10 +43,10 @@ test {
dependencies {
// JUnit Tests
testImplementation 'junit:junit:4.12'
testImplementation 'org.assertj:assertj-core:3.8.0'
testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0")
testImplementation 'org.mockito:mockito-core:3.+'
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.assertj:assertj-core:3.23.1'
testImplementation('org.junit.jupiter:junit-jupiter-api:5.9.0')
testImplementation 'org.mockito:mockito-core:4.8.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
@@ -56,37 +56,37 @@ dependencies {
implementation 'com.github.nwaldispuehl:java-lame:v3.98.4'
//mavenCentral/jcenter imports
implementation 'ch.qos.logback:logback-classic:1.2.3'
implementation 'ch.qos.logback:logback-core:1.2.3'
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.9.8'
implementation 'com.fazecast:jSerialComm:2.5.0'
implementation 'ch.qos.logback:logback-classic:1.4.4'
implementation 'ch.qos.logback:logback-core:1.4.4'
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.14.0'
implementation 'com.fazecast:jSerialComm:2.9.2'
implementation 'com.github.jiconfont:jiconfont-font_awesome:4.7.0.1'
implementation 'com.github.jiconfont:jiconfont-javafx:1.0.0'
implementation 'com.github.jiconfont:jiconfont-swing:1.0.1'
implementation 'com.github.wendykierp:JTransforms:3.1'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.google.guava:guava:27.0.1-jre'
implementation 'com.google.code.gson:gson:2.10'
implementation 'com.google.guava:guava:31.1-jre'
implementation 'com.jidesoft:jide-oss:3.6.18'
implementation 'com.miglayout:miglayout-swing:5.2'
implementation 'com.miglayout:miglayout-swing:11.0'
implementation 'com.mpatric:mp3agic:0.9.1'
implementation 'commons-io:commons-io:2.7'
implementation 'commons-io:commons-io:2.11.0'
implementation 'eu.hansolo:charts:1.0.5'
implementation 'io.github.dsheirer:radio-reference-api:15.1.8'
implementation 'javax.usb:usb-api:1.0.2'
implementation 'net.coderazzi:tablefilter-swing:5.4.0'
implementation 'org.apache.commons:commons-compress:1.20'
implementation 'org.apache.commons:commons-lang3:3.8.1'
implementation 'net.coderazzi:tablefilter-swing:5.5.4'
implementation 'org.apache.commons:commons-compress:1.21'
implementation 'org.apache.commons:commons-lang3:3.12.0'
implementation 'org.apache.commons:commons-math3:3.6.1'
implementation 'org.apache.commons:commons-csv:1.9.0'
implementation 'org.apache.mina:mina-core:2.1.3'
implementation 'org.apache.mina:mina-http:2.1.3'
implementation 'org.controlsfx:controlsfx:11.1.0'
implementation 'org.rauschig:jarchivelib:1.0.0'
implementation 'org.slf4j:slf4j-api:1.7.25'
implementation 'org.apache.mina:mina-core:2.2.1'
implementation 'org.apache.mina:mina-http:2.2.1'
implementation 'org.controlsfx:controlsfx:11.1.2'
implementation 'org.rauschig:jarchivelib:1.2.0'
implementation 'org.slf4j:slf4j-api:2.0.3'
implementation 'org.usb4java:libusb4java:1.3.0'
implementation 'org.usb4java:usb4java:1.3.0'
implementation 'org.usb4java:usb4java-javax:1.3.0'
implementation 'io.github.dsheirer:libusb4java-darwin-aarch64:1.3.0' //usb4java native lib for OSX M1 cpu
implementation 'io.github.dsheirer:libusb4java-darwin-aarch64:1.3.1' //usb4java native lib for OSX M1 cpu
implementation 'pl.edu.icm:JLargeArrays:1.6'
}
@@ -139,11 +139,11 @@ String targetWindowsX86_64 = 'windows-x86_64-v' + version
* author's development environment, but can be changed to your environment if you want to use this build pattern.
*/
String jdk_base = '/home/denny/java_jdks/'
String jdk_linux_aarch64 = jdk_base + 'linux-arm64/jdk-17.0.2-full'
String jdk_linux_x86_64 = jdk_base + 'linux-x64/jdk-17.0.2-full'
String jdk_osx_x86_64 = jdk_base + 'osx-x64/jdk-17.0.2-full.jdk'
String jdk_osx_aarch64 = jdk_base + 'osx-arm64/jdk-17.0.2-full.jdk'
String jdk_windows_x86_64 = jdk_base + 'windows-x64/jdk-17.0.2-full'
String jdk_linux_aarch64 = jdk_base + 'linux-arm64/jdk-19.0.1-full'
String jdk_linux_x86_64 = jdk_base + 'linux-x64/jdk-19.0.1-full'
String jdk_osx_x86_64 = jdk_base + 'osx-x64/jdk-19.0.1-full.jdk'
String jdk_osx_aarch64 = jdk_base + 'osx-arm64/jdk-19.0.1-full.jdk'
String jdk_windows_x86_64 = jdk_base + 'windows-x64/jdk-19.0.1-full'
boolean hasTargetJdks = file(jdk_linux_x86_64).exists() || file(jdk_linux_aarch64).exists() ||
file(jdk_osx_x86_64).exists() || file(jdk_osx_aarch64).exists() || file(jdk_windows_x86_64).exists()
@@ -172,19 +172,19 @@ runtime {
println("Building all runtime images")
println("The [ > jre: ] build phase downloads several target JDKs and this may take a while ... please wait")
targetPlatform(targetLinuxAarch64) {
jdkHome = jdkDownload("https://download.bell-sw.com/java/17.0.2+9/bellsoft-jdk17.0.2+9-linux-aarch64-full.tar.gz")
jdkHome = jdkDownload("https://download.bell-sw.com/java/19.0.1+11/bellsoft-jdk19.0.1+11-linux-aarch64-full.tar.gz")
}
targetPlatform(targetLinuxX86_64) {
jdkHome = jdkDownload("https://download.bell-sw.com/java/17.0.2+9/bellsoft-jdk17.0.2+9-linux-amd64-full.tar.gz")
jdkHome = jdkDownload("https://download.bell-sw.com/java/19.0.1+11/bellsoft-jdk19.0.1+11-linux-amd64-full.tar.gz")
}
targetPlatform(targetOsxAarch64) {
jdkHome = jdkDownload("https://download.bell-sw.com/java/17.0.2+9/bellsoft-jdk17.0.2+9-macos-aarch64-full.tar.gz")
jdkHome = jdkDownload("https://download.bell-sw.com/java/19.0.1+11/bellsoft-jdk19.0.1+11-macos-aarch64-full.tar.gz")
}
targetPlatform(targetOsxX86_64) {
jdkHome = jdkDownload("https://download.bell-sw.com/java/17.0.2+9/bellsoft-jdk17.0.2+9-macos-amd64-full.tar.gz")
jdkHome = jdkDownload("https://download.bell-sw.com/java/19.0.1+11/bellsoft-jdk19.0.1+11-macos-amd64-full.tar.gz")
}
targetPlatform(targetWindowsX86_64) {
jdkHome = jdkDownload("https://download.bell-sw.com/java/17.0.2+9/bellsoft-jdk17.0.2+9-windows-amd64-full.zip")
jdkHome = jdkDownload("https://download.bell-sw.com/java/19.0.1+11/bellsoft-jdk19.0.1+11-windows-amd64-full.zip")
}
}
//Build using pre-downloaded JDKs

Binary file not shown.

View File

@@ -1,5 +1,24 @@
#
# ******************************************************************************
# Copyright (C) 2014-2022 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/>
# *****************************************************************************
#
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-rc-3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

290
gradlew vendored
View File

@@ -1,94 +1,132 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright 2015 the original author or authors.
# ******************************************************************************
# Copyright (C) 2014-2022 Dennis Sheirer
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 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.
#
# https://www.apache.org/licenses/LICENSE-2.0
# 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.
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>
# *****************************************************************************
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -97,7 +135,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@@ -105,79 +143,95 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

25
gradlew.bat vendored
View File

@@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -51,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -61,28 +64,14 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 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/>
* * *****************************************************************************
* 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.alias;

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 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/>
* * *****************************************************************************
* 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.alias;

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 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/>
* * *****************************************************************************
* 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.alias;

View File

@@ -39,7 +39,7 @@ public class AudioSegmentBroadcaster<T extends AudioSegment> extends Broadcaster
@Override
public void broadcast(T audioSegment)
{
for(Listener<T> listener : mListeners)
for(Listener<T> listener : getListeners())
{
audioSegment.incrementConsumerCount();
listener.receive(audioSegment);

View File

@@ -24,7 +24,10 @@ import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.Float;
import java.lang.Math;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
public class AudioUtils
@@ -78,4 +81,43 @@ public class AudioUtils
return stream.toByteArray();
}
/**
* Normalize audio samples
*/
public static List<float[]> normalize(List<float[]> audioBuffers)
{
float targetMax = 0.95f; // -0.44dBFS
float max = 0.1f; // Initialize at 0.1 (-20dBFS) to limit maximum gain
for(float[] audioBuffer: audioBuffers)
{
for(float value: audioBuffer)
{
float newMax = Math.max(max, Math.abs(value));
if(!Float.isNaN(newMax))
{
max = newMax;
}
}
}
if(targetMax == max)
{
return audioBuffers;
}
float gain = targetMax / max;
for(float[] audioBuffer: audioBuffers)
{
for(int i=0;i<audioBuffer.length;i++)
{
audioBuffer[i] *= gain;
}
}
return audioBuffers;
}
}

View File

@@ -42,7 +42,7 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
private final static Logger mLog = LoggerFactory.getLogger(AudioStreamingBroadcaster.class);
public static final int PROCESSOR_RUN_INTERVAL_MS = 1000;
private ScheduledFuture mRecordingQueueProcessorFuture;
private ScheduledFuture<?> mRecordingQueueProcessorFuture;
private RecordingQueueProcessor mRecordingQueueProcessor = new RecordingQueueProcessor();
private Queue<AudioRecording> mAudioRecordingQueue = new LinkedTransferQueue<>();
@@ -52,6 +52,10 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
private long mMaximumRecordingAge;
private AtomicBoolean mStreaming = new AtomicBoolean();
protected boolean mInlineActive = false;
protected int mInlineInterval;
protected int mInlineRemaining = -1;
/**
* AudioBroadcaster for streaming audio recordings to a remote streaming audio server. Audio recordings are
* generated by an internal StreamManager that converts an inbound stream of AudioPackets into a recording of the
@@ -89,7 +93,7 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
/**
* Broadcast binary audio data frames or sequences.
*/
protected abstract void broadcastAudio(byte[] audio);
protected abstract void broadcastAudio(byte[] audio, IdentifierCollection identifierCollection);
/**
* Protocol-specific metadata updater
@@ -205,13 +209,15 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
super.setBroadcastState(state);
if(mBroadcastState.get() instanceof BroadcastState && ((BroadcastState)mBroadcastState.get()).isErrorState())
if(mBroadcastState.get() != null && mBroadcastState.get().isErrorState())
{
stop();
}
if(!connected())
{
//Reset inline metadata
mInlineRemaining = -1;
//Remove all pending audio recordings
while(!mAudioRecordingQueue.isEmpty())
{
@@ -265,9 +271,9 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
{
private AtomicBoolean mProcessing = new AtomicBoolean();
private ByteArrayInputStream mInputStream;
private IdentifierCollection mInputIdentifierCollection;
private long mFinalSilencePadding = 0;
private int mBytesStreamedActual = 0;
private int mBytesStreamedRequired = 0;
private int mBytesToStreamPerInterval = 0;
@Override
public void run()
@@ -278,51 +284,44 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
{
if(mInputStream == null || mInputStream.available() <= 0)
{
if(mFinalSilencePadding > 0)
{
List<byte[]> finalSilence = mSilenceGenerator.generate(mFinalSilencePadding);
for(byte[] silence: finalSilence)
{
broadcastAudio(silence);
}
mFinalSilencePadding = 0;
}
nextRecording();
}
if(mInputStream != null)
{
//We need to stream at 13.888 fps (144 byte frame) to achieve 2000 Bps or 16 kbps
mBytesStreamedRequired += 2000; //2000 bytes per second for 16 kbps data rate
int bytesToStream = mBytesStreamedRequired - mBytesStreamedActual;
//Trim length to whole-frame intervals (144 byte frame)
bytesToStream -= (bytesToStream % 144);
int length = FastMath.min(bytesToStream, mInputStream.available());
int length = FastMath.min(mBytesToStreamPerInterval, mInputStream.available());
byte[] audio = new byte[length];
try
{
mBytesStreamedActual += mInputStream.read(audio);
broadcastAudio(audio);
int read = mInputStream.read(audio);
broadcastAudio(audio, mInputIdentifierCollection);
}
catch(IOException ioe)
{
mLog.error("Error reading from in-memory audio recording input stream", ioe);
}
//If this is the final frame fragment then append silence padding to fill the final interval segment
if(length < mBytesToStreamPerInterval && mFinalSilencePadding > 0)
{
List<byte[]> finalSilence = mSilenceGenerator.generate(mFinalSilencePadding);
for(byte[] silence: finalSilence)
{
broadcastAudio(silence, null);
}
mFinalSilencePadding = 0;
}
}
else
{
List<byte[]> silenceFrames = mSilenceGenerator.generate(PROCESSOR_RUN_INTERVAL_MS);
for(byte[] silence: silenceFrames)
{
broadcastAudio(silence);
broadcastAudio(silence, null);
}
}
}
@@ -340,9 +339,6 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
*/
private void nextRecording()
{
mBytesStreamedActual = 0;
mBytesStreamedRequired = 0;
boolean metadataUpdateRequired = false;
if(mInputStream != null)
@@ -354,6 +350,7 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
}
mInputStream = null;
mInputIdentifierCollection = null;
//Peek at the next recording but don't remove it from the queue yet, so we can inspect the start time for
//age limits and/or delay elapsed
@@ -381,9 +378,14 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
{
byte[] audio = Files.readAllBytes(nextRecording.getPath());
if(audio != null && audio.length > 0)
if(audio.length > 0)
{
//Calculate how many bytes we'll send with each processor run interval
double intervals = (double)nextRecording.getRecordingLength() / (double)PROCESSOR_RUN_INTERVAL_MS;
mBytesToStreamPerInterval = (int)((double)audio.length / intervals);
mInputStream = new ByteArrayInputStream(audio);
mInputIdentifierCollection = nextRecording.getIdentifierCollection();
mFinalSilencePadding = PROCESSOR_RUN_INTERVAL_MS -
(nextRecording.getRecordingLength() % PROCESSOR_RUN_INTERVAL_MS);
@@ -408,6 +410,7 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
"stream recording [" + nextRecording.getPath().toString() + "] - skipping recording - ", ioe);
mInputStream = null;
mInputIdentifierCollection = null;
metadataUpdateRequired = false;
}

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 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/>
* * *****************************************************************************
* 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.audio.broadcast;

View File

@@ -30,10 +30,8 @@ import io.github.dsheirer.audio.broadcast.shoutcast.v1.ShoutcastV1AudioBroadcast
import io.github.dsheirer.audio.broadcast.shoutcast.v1.ShoutcastV1Configuration;
import io.github.dsheirer.audio.broadcast.shoutcast.v2.ShoutcastV2AudioStreamingBroadcaster;
import io.github.dsheirer.audio.broadcast.shoutcast.v2.ShoutcastV2Configuration;
import io.github.dsheirer.audio.convert.IAudioConverter;
import io.github.dsheirer.audio.convert.ISilenceGenerator;
import io.github.dsheirer.audio.convert.InputAudioFormat;
import io.github.dsheirer.audio.convert.MP3AudioConverter;
import io.github.dsheirer.audio.convert.MP3Setting;
import io.github.dsheirer.audio.convert.MP3SilenceGenerator;
import io.github.dsheirer.preference.UserPreferences;
@@ -88,26 +86,6 @@ public class BroadcastFactory
return null;
}
/**
* Creates an audio convert to convert from 8 kHz PCM audio to the specified format
*
* @param configuration containing the requested output audio format
* @return audio convert or null
*/
public static IAudioConverter getAudioConverter(BroadcastConfiguration configuration, InputAudioFormat inputAudioFormat,
MP3Setting mp3Setting)
{
switch(configuration.getBroadcastFormat())
{
case MP3:
return new MP3AudioConverter(inputAudioFormat, mp3Setting);
default:
mLog.info("Unrecognized broadcastAudio format: " + configuration.getBroadcastFormat().name());
}
return null;
}
/**
* Creates a broadcastAudio configuration for the specified server type and format
*

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 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/>
* * *****************************************************************************
* 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.audio.broadcast;

View File

@@ -68,6 +68,7 @@ public class BroadcastifyCallBroadcaster extends AbstractAudioBroadcaster<Broadc
private static final String MULTIPART_TYPE = "multipart";
private static final String DEFAULT_SUBTYPE = "form-data";
private static final String MULTIPART_FORM_DATA = MULTIPART_TYPE + "/" + DEFAULT_SUBTYPE;
private ScheduledFuture<?> mBroadcastifyTestFuture;
private Queue<AudioRecording> mAudioRecordingQueue = new LinkedTransferQueue<>();
private ScheduledFuture<?> mAudioRecordingProcessorFuture;
private HttpClient mHttpClient = HttpClient.newBuilder()
@@ -109,6 +110,12 @@ public class BroadcastifyCallBroadcaster extends AbstractAudioBroadcaster<Broadc
setBroadcastState(BroadcastState.ERROR);
}
if(mBroadcastifyTestFuture == null && getBroadcastConfiguration().isTestEnabled())
{
// Test periodically so we don't get marked offline due to radio inactivity
mBroadcastifyTestFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(new BroadcastifyCallTest(), getBroadcastConfiguration().getTestInterval(), getBroadcastConfiguration().getTestInterval(), TimeUnit.MINUTES);
}
if(mAudioRecordingProcessorFuture == null)
{
mAudioRecordingProcessorFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(new AudioRecordingProcessor(),
@@ -122,6 +129,11 @@ public class BroadcastifyCallBroadcaster extends AbstractAudioBroadcaster<Broadc
@Override
public void stop()
{
if(mBroadcastifyTestFuture != null)
{
mBroadcastifyTestFuture.cancel(true);
mBroadcastifyTestFuture = null;
}
if(mAudioRecordingProcessorFuture != null)
{
mAudioRecordingProcessorFuture.cancel(true);
@@ -131,6 +143,23 @@ public class BroadcastifyCallBroadcaster extends AbstractAudioBroadcaster<Broadc
}
}
public class BroadcastifyCallTest implements Runnable
{
@Override
public void run()
{
String response = testConnection(getBroadcastConfiguration());
if(response != null && response.toLowerCase().startsWith("ok"))
{
mLog.info("Broadcastify Calls keep-alive success");
}
else
{
mLog.info("Broadcastify Calls keep-alive failure");
}
}
}
/**
* Prepares for disposal
*/
@@ -418,28 +447,20 @@ public class BroadcastifyCallBroadcaster extends AbstractAudioBroadcaster<Broadc
*/
private static String getTo(AudioRecording audioRecording)
{
List<Identifier> toIdentifiers = audioRecording.getIdentifierCollection().getIdentifiers(Role.TO);
Identifier identifier = audioRecording.getIdentifierCollection().getToIdentifier();
//Format a patch group first, if there are multiples
for(Identifier identifier: toIdentifiers)
if(identifier instanceof PatchGroupIdentifier patchGroupIdentifier)
{
if(identifier instanceof PatchGroupIdentifier patchGroupIdentifier)
{
return format(patchGroupIdentifier);
}
return format(patchGroupIdentifier);
}
for(Identifier identifier: toIdentifiers)
else if(identifier instanceof TalkgroupIdentifier talkgroupIdentifier)
{
if(identifier instanceof TalkgroupIdentifier talkgroupIdentifier)
{
return String.valueOf(RadioReferenceDecoder.convertToRadioReferenceTalkgroup(talkgroupIdentifier.getValue(),
talkgroupIdentifier.getProtocol()));
}
else if(identifier instanceof RadioIdentifier radioIdentifier)
{
return radioIdentifier.getValue().toString();
}
return String.valueOf(RadioReferenceDecoder.convertToRadioReferenceTalkgroup(talkgroupIdentifier.getValue(),
talkgroupIdentifier.getProtocol()));
}
else if(identifier instanceof RadioIdentifier radioIdentifier)
{
return radioIdentifier.getValue().toString();
}
return "0";

View File

@@ -24,7 +24,9 @@ import io.github.dsheirer.audio.broadcast.BroadcastConfiguration;
import io.github.dsheirer.audio.broadcast.BroadcastFormat;
import io.github.dsheirer.audio.broadcast.BroadcastServerType;
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
@@ -42,6 +44,8 @@ public class BroadcastifyCallConfiguration extends BroadcastConfiguration
private IntegerProperty mSystemID = new SimpleIntegerProperty();
private StringProperty mApiKey = new SimpleStringProperty();
private BooleanProperty mTestEnabled= new SimpleBooleanProperty(false);
private IntegerProperty mTestInterval = new SimpleIntegerProperty(15);
/**
* Constructor for faster jackson
@@ -128,6 +132,34 @@ public class BroadcastifyCallConfiguration extends BroadcastConfiguration
return BroadcastServerType.BROADCASTIFY_CALL;
}
/**
* Indicates if this instance should schedule tests after connecting
*/
@JacksonXmlProperty(isAttribute = true, localName = "test_enabled")
public boolean isTestEnabled()
{
return mTestEnabled.get();
}
public void setTestEnabled(boolean enabled)
{
mTestEnabled.set(enabled);
}
/**
* Indicates the interval at which tests should be performed while enabled
*/
@JacksonXmlProperty(isAttribute = true, localName = "test_interval")
public int getTestInterval()
{
return mTestInterval.get();
}
public void setTestInterval(int interval)
{
mTestInterval.set(interval);
}
@Override
public BroadcastConfiguration copyOf()
{

View File

@@ -54,6 +54,7 @@ public class BroadcastifyFeedConfiguration extends IcecastTCPConfiguration
setBitRate(16);
setChannels(1);
setSampleRate(8000);
setInline(true);
}
public static BroadcastifyFeedConfiguration from(UserFeedBroadcast userFeedBroadcast)
@@ -86,9 +87,9 @@ public class BroadcastifyFeedConfiguration extends IcecastTCPConfiguration
copy.setName(getName());
copy.setHost(getHost());
copy.setPort(getPort());
copy.setInline(getInline());
copy.setPassword(getPassword());
copy.setDelay(getDelay());
copy.setEnabled(false);
//Icecast Configuration Parameters

View File

@@ -28,7 +28,7 @@ import io.github.dsheirer.audio.convert.MP3Setting;
public abstract class IcecastAudioBroadcaster extends AudioStreamingBroadcaster
{
private IBroadcastMetadataUpdater mMetadataUpdater;
private AliasModel mAliasModel;
protected AliasModel mAliasModel;
public IcecastAudioBroadcaster(BroadcastConfiguration broadcastConfiguration, InputAudioFormat inputAudioFormat,
MP3Setting mp3Setting, AliasModel aliasModel)

View File

@@ -23,6 +23,8 @@ import io.github.dsheirer.alias.Alias;
import io.github.dsheirer.alias.AliasList;
import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.audio.broadcast.IBroadcastMetadataUpdater;
import io.github.dsheirer.audio.broadcast.icecast.IcecastConfiguration;
import io.github.dsheirer.audio.broadcast.icecast.IcecastMetadata;
import io.github.dsheirer.identifier.Form;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.identifier.IdentifierClass;
@@ -73,6 +75,12 @@ public class IcecastBroadcastMetadataUpdater implements IBroadcastMetadataUpdate
*/
public void update(IdentifierCollection identifierCollection)
{
if(mIcecastConfiguration.hasInline())
{
// Never send out-of-band metadata if inline metadata is enabled.
return;
}
StringBuilder sb = new StringBuilder();
try
@@ -84,7 +92,7 @@ public class IcecastBroadcastMetadataUpdater implements IBroadcastMetadataUpdate
sb.append("/admin/metadata?mode=updinfo&mount=");
sb.append(URLEncoder.encode(mIcecastConfiguration.getMountPoint(), UTF8));
sb.append("&charset=UTF%2d8");
sb.append("&song=").append(URLEncoder.encode(getSong(identifierCollection), UTF8));
sb.append("&song=").append(URLEncoder.encode(IcecastMetadata.getTitle(identifierCollection, mAliasModel), UTF8));
}
catch(UnsupportedEncodingException uee)
{
@@ -157,82 +165,4 @@ public class IcecastBroadcastMetadataUpdater implements IBroadcastMetadataUpdate
}
}
/**
* Creates the song information for a metadata update
*/
private String getSong(IdentifierCollection identifierCollection)
{
StringBuilder sb = new StringBuilder();
if(identifierCollection != null)
{
AliasList aliasList = mAliasModel.getAliasList(identifierCollection);
Identifier to = identifierCollection.getIdentifier(IdentifierClass.USER, Form.PATCH_GROUP, Role.TO);
if(to == null)
{
to = identifierCollection.getIdentifier(IdentifierClass.USER, Form.TALKGROUP, Role.TO);
}
if(to == null)
{
List<Identifier> toIdentifiers = identifierCollection.getIdentifiers(Role.TO);
if(!toIdentifiers.isEmpty())
{
to = toIdentifiers.get(0);
}
}
if(to != null)
{
sb.append("TO:").append(to);
List<Alias> aliases = aliasList.getAliases(to);
if(aliases != null && !aliases.isEmpty())
{
sb.append(" ").append(Joiner.on(", ").skipNulls().join(aliases));
}
}
else
{
sb.append("TO:UNKNOWN");
}
Identifier from = identifierCollection.getIdentifier(IdentifierClass.USER, Form.RADIO, Role.FROM);
if(from == null)
{
List<Identifier> fromIdentifiers = identifierCollection.getIdentifiers(Role.FROM);
if(!fromIdentifiers.isEmpty())
{
from = fromIdentifiers.get(0);
}
}
if(from != null)
{
sb.append(" FROM:").append(from);
List<Alias> aliases = aliasList.getAliases(from);
if(aliases != null && !aliases.isEmpty())
{
sb.append(" ").append(Joiner.on(", ").skipNulls().join(aliases));
}
}
else
{
sb.append(" FROM:UNKNOWN");
}
}
else
{
sb.append("Scanning ....");
}
return sb.toString();
}
}

View File

@@ -45,6 +45,7 @@ public abstract class IcecastConfiguration extends BroadcastConfiguration
private int mChannels = 1;
private int mSampleRate = 8000;
private String mURL;
private boolean mInline = true;
public IcecastConfiguration(BroadcastFormat format)
{
@@ -275,6 +276,37 @@ public abstract class IcecastConfiguration extends BroadcastConfiguration
return mURL != null;
}
/**
* Control whether metadata is sent inline or out-of-band.
*/
@JacksonXmlProperty(isAttribute = true, localName = "inline")
public boolean getInline()
{
return mInline;
}
@JsonIgnore
public int getInlineInterval()
{
if (hasBitRate())
{
// Interval = BitRate * 1000 / 8 = 1 second
return getBitRate() * 125;
}
return -1;
}
public void setInline(boolean inline)
{
mInline = inline;
}
public boolean hasInline()
{
// Bitrate must be known to calculate metadata interval
return mInline != false && hasBitRate();
}
@Override
public boolean isValid()
{

View File

@@ -20,9 +20,11 @@ package io.github.dsheirer.audio.broadcast.icecast;
import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.audio.broadcast.BroadcastState;
import io.github.dsheirer.audio.broadcast.icecast.IcecastMetadata;
import io.github.dsheirer.audio.convert.InputAudioFormat;
import io.github.dsheirer.audio.convert.MP3AudioConverter;
import io.github.dsheirer.audio.convert.MP3Setting;
import io.github.dsheirer.identifier.IdentifierCollection;
import io.github.dsheirer.properties.SystemProperties;
import io.github.dsheirer.util.ThreadPool;
import org.apache.mina.core.RuntimeIoException;
@@ -42,6 +44,7 @@ import org.slf4j.LoggerFactory;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -80,14 +83,41 @@ public class IcecastHTTPAudioBroadcaster extends IcecastAudioBroadcaster
* Broadcasts the audio frame or sequence
*/
@Override
protected void broadcastAudio(byte[] audio)
protected void broadcastAudio(byte[] audio, IdentifierCollection identifierCollection)
{
if(audio != null && audio.length > 0 && connect() && mStreamingSession != null && mStreamingSession.isConnected())
{
IoBuffer buffer = IoBuffer.allocate(audio.length);
buffer.put(audio);
buffer.flip();
if(mInlineActive)
{
byte[] metadata = IcecastMetadata.formatInline(IcecastMetadata.getTitle(identifierCollection, mAliasModel)).getBytes();
buffer.setAutoExpand(true);
if (mInlineRemaining == -1)
{
mInlineRemaining = mInlineInterval;
}
int audioOffset = 0;
while(audioOffset < audio.length)
{
byte[] chunk = Arrays.copyOfRange(audio, audioOffset, Math.min(audioOffset + mInlineRemaining, audio.length));
mInlineRemaining -= chunk.length;
audioOffset += chunk.length;
buffer.put(chunk);
if(mInlineRemaining == 0)
{
mInlineRemaining = mInlineInterval;
buffer.put(metadata);
}
}
buffer.shrink();
}
else
{
buffer.put(audio);
}
buffer.flip();
mStreamingSession.write(buffer);
}
}
@@ -238,6 +268,17 @@ public class IcecastHTTPAudioBroadcaster extends IcecastAudioBroadcaster
{
mHTTPHeaders.put(IcecastHeader.BITRATE.getValue(), String.valueOf(getConfiguration().getBitRate()));
}
if(getConfiguration().hasInline())
{
mInlineActive = true;
mInlineInterval = getConfiguration().getInlineInterval();
mHTTPHeaders.put(IcecastHeader.METAINT.getValue(), String.valueOf(mInlineInterval));
}
else
{
mInlineActive = false;
}
}
return mHTTPHeaders;

View File

@@ -55,6 +55,7 @@ public class IcecastHTTPConfiguration extends IcecastConfiguration
copy.setName(getName());
copy.setHost(getHost());
copy.setPort(getPort());
copy.setInline(getInline());
copy.setPassword(getPassword());
copy.setDelay(getDelay());
copy.setEnabled(false);

View File

@@ -33,6 +33,7 @@ public enum IcecastHeader
PUBLIC("ice-public"),
URL("ice-url"),
USER_AGENT("User-Agent"),
METAINT("icy-metaint"),
UNKNOWN("unknown");

View File

@@ -0,0 +1,138 @@
/*
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 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.audio.broadcast.icecast;
import com.google.common.base.Joiner;
import io.github.dsheirer.alias.Alias;
import io.github.dsheirer.alias.AliasList;
import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.audio.broadcast.icecast.IcecastConfiguration;
import io.github.dsheirer.identifier.Form;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.identifier.IdentifierClass;
import io.github.dsheirer.identifier.IdentifierCollection;
import io.github.dsheirer.identifier.Role;
import io.github.dsheirer.properties.SystemProperties;
import io.github.dsheirer.util.ThreadPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
public class IcecastMetadata
{
private final static Logger mLog = LoggerFactory.getLogger(IcecastMetadata.class);
/**
* Creates the title for a metadata update
*/
public static String getTitle(IdentifierCollection identifierCollection, AliasModel AliasModel)
{
StringBuilder sb = new StringBuilder();
if(identifierCollection != null)
{
AliasList aliasList = AliasModel.getAliasList(identifierCollection);
Identifier to = identifierCollection.getIdentifier(IdentifierClass.USER, Form.PATCH_GROUP, Role.TO);
if(to == null)
{
to = identifierCollection.getIdentifier(IdentifierClass.USER, Form.TALKGROUP, Role.TO);
}
if(to == null)
{
List<Identifier> toIdentifiers = identifierCollection.getIdentifiers(Role.TO);
if(!toIdentifiers.isEmpty())
{
to = toIdentifiers.get(0);
}
}
if(to != null)
{
sb.append("TO:").append(to);
List<Alias> aliases = aliasList.getAliases(to);
if(aliases != null && !aliases.isEmpty())
{
sb.append(" ").append(Joiner.on(", ").skipNulls().join(aliases));
}
}
else
{
sb.append("TO:UNKNOWN");
}
Identifier from = identifierCollection.getIdentifier(IdentifierClass.USER, Form.RADIO, Role.FROM);
if(from == null)
{
List<Identifier> fromIdentifiers = identifierCollection.getIdentifiers(Role.FROM);
if(!fromIdentifiers.isEmpty())
{
from = fromIdentifiers.get(0);
}
}
if(from != null)
{
sb.append(" FROM:").append(from);
List<Alias> aliases = aliasList.getAliases(from);
if(aliases != null && !aliases.isEmpty())
{
sb.append(" ").append(Joiner.on(", ").skipNulls().join(aliases));
}
}
else
{
sb.append(" FROM:UNKNOWN");
}
}
else
{
sb.append("Scanning...");
}
return sb.toString();
}
public static String formatInline(String title)
{
title = "StreamTitle='" + title + "';";
int chunks = (int)Math.ceil((title.length() + 1) / 16.0d);
int nulls = (chunks * 16) - title.length();
char[] padding = new char[nulls];
StringBuilder sb = new StringBuilder();
sb.append((char)chunks).append(title).append(padding);
return sb.toString();
}
}

View File

@@ -21,9 +21,11 @@ package io.github.dsheirer.audio.broadcast.icecast;
import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.audio.broadcast.BroadcastState;
import io.github.dsheirer.audio.broadcast.icecast.codec.IcecastCodecFactory;
import io.github.dsheirer.audio.broadcast.icecast.IcecastMetadata;
import io.github.dsheirer.audio.convert.InputAudioFormat;
import io.github.dsheirer.audio.convert.MP3AudioConverter;
import io.github.dsheirer.audio.convert.MP3Setting;
import io.github.dsheirer.identifier.IdentifierCollection;
import io.github.dsheirer.properties.SystemProperties;
import io.github.dsheirer.util.ThreadPool;
import org.apache.mina.core.RuntimeIoException;
@@ -39,13 +41,14 @@ import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.nio.channels.UnresolvedAddressException;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
public class IcecastTCPAudioBroadcaster extends IcecastAudioBroadcaster
{
private final static Logger mLog = LoggerFactory.getLogger(IcecastTCPAudioBroadcaster.class);
private final static String TERMINATOR = "\r\n";
private final static String TERMINATOR = "\n";
private final static String SEPARATOR = ":";
private static final long RECONNECT_INTERVAL_MILLISECONDS = 3000; //3 seconds
private static final long CONNECTION_ATTEMPT_TIMEOUT_MILLISECONDS = 5000; //5 seconds
@@ -78,11 +81,35 @@ public class IcecastTCPAudioBroadcaster extends IcecastAudioBroadcaster
* Broadcasts the audio frame or sequence
*/
@Override
protected void broadcastAudio(byte[] audio)
protected void broadcastAudio(byte[] audio, IdentifierCollection identifierCollection)
{
if(audio != null && audio.length > 0 && connect() && mStreamingSession != null && mStreamingSession.isConnected())
{
mStreamingSession.write(audio);
if(mInlineActive)
{
byte[] metadata = IcecastMetadata.formatInline(IcecastMetadata.getTitle(identifierCollection, mAliasModel)).getBytes();
if (mInlineRemaining == -1)
{
mInlineRemaining = mInlineInterval;
}
int audioOffset = 0;
while(audioOffset < audio.length)
{
byte[] chunk = Arrays.copyOfRange(audio, audioOffset, Math.min(audioOffset + mInlineRemaining, audio.length));
mInlineRemaining -= chunk.length;
audioOffset += chunk.length;
mStreamingSession.write(chunk);
if(mInlineRemaining == 0)
{
mInlineRemaining = mInlineInterval;
mStreamingSession.write(metadata);
}
}
}
else
{
mStreamingSession.write(audio);
}
}
}
@@ -238,7 +265,18 @@ public class IcecastTCPAudioBroadcaster extends IcecastAudioBroadcaster
.append(getConfiguration().getDescription()).append(TERMINATOR);
}
sb.append(TERMINATOR).append(TERMINATOR);
if(getConfiguration().hasInline())
{
mInlineActive = true;
mInlineInterval = getConfiguration().getInlineInterval();
sb.append(IcecastHeader.METAINT.getValue()).append(SEPARATOR)
.append(String.valueOf(mInlineInterval))
.append(TERMINATOR);
}
else
{
mInlineActive = false;
}
session.write(sb.toString());
}

View File

@@ -63,6 +63,7 @@ public class IcecastTCPConfiguration extends IcecastConfiguration
copy.setName(getName());
copy.setHost(getHost());
copy.setPort(getPort());
copy.setInline(getInline());
copy.setPassword(getPassword());
copy.setDelay(getDelay());
copy.setEnabled(false);

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2016 Dennis Sheirer
/*
* *****************************************************************************
* Copyright (C) 2014-2022 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
@@ -14,8 +14,8 @@
*
* 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.audio.broadcast.icecast.codec;
import org.apache.mina.core.buffer.IoBuffer;

View File

@@ -24,6 +24,7 @@ import io.github.dsheirer.audio.broadcast.BroadcastState;
import io.github.dsheirer.audio.broadcast.IBroadcastMetadataUpdater;
import io.github.dsheirer.audio.convert.InputAudioFormat;
import io.github.dsheirer.audio.convert.MP3Setting;
import io.github.dsheirer.identifier.IdentifierCollection;
import io.github.dsheirer.util.ThreadPool;
import org.apache.mina.core.RuntimeIoException;
import org.apache.mina.core.buffer.IoBuffer;
@@ -93,7 +94,7 @@ public class ShoutcastV1AudioBroadcaster extends AudioStreamingBroadcaster
* Broadcasts the audio frame or sequence
*/
@Override
protected void broadcastAudio(byte[] audio)
protected void broadcastAudio(byte[] audio, IdentifierCollection identifierCollection)
{
if(audio != null && audio.length > 0 && connect() && mStreamingSession != null && mStreamingSession.isConnected())
{

View File

@@ -109,7 +109,7 @@ public class ShoutcastV2AudioStreamingBroadcaster extends AudioStreamingBroadcas
* Broadcasts the audio frame or sequence
*/
@Override
protected void broadcastAudio(byte[] audio)
protected void broadcastAudio(byte[] audio, IdentifierCollection identifierCollection)
{
//Dispatch any queued metadata messages
UltravoxMessage metadataMessage = mMetadataMessageQueue.poll();

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2016 Dennis Sheirer
/*
* *****************************************************************************
* Copyright (C) 2014-2022 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
@@ -14,8 +14,8 @@
*
* 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.audio.broadcast.shoutcast.v2.ultravox;
import io.github.dsheirer.audio.broadcast.BroadcastFormat;

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2016 Dennis Sheirer
/*
* *****************************************************************************
* Copyright (C) 2014-2022 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
@@ -14,8 +14,8 @@
*
* 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.audio.broadcast.shoutcast.v2.ultravox;
import io.github.dsheirer.bits.BinaryMessage;

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2016 Dennis Sheirer
/*
* *****************************************************************************
* Copyright (C) 2014-2022 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
@@ -14,8 +14,8 @@
*
* 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.audio.broadcast.shoutcast.v2.ultravox;
public class UltravoxMessageFactory

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2021 Dennis Sheirer
* Copyright (C) 2014-2022 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

View File

@@ -18,19 +18,19 @@
*/
package io.github.dsheirer.audio.convert;
import io.github.dsheirer.audio.AudioUtils;
import io.github.dsheirer.dsp.filter.resample.RealResampler;
import io.github.dsheirer.sample.ConversionUtils;
import net.sourceforge.lame.lowlevel.LameEncoder;
import net.sourceforge.lame.mp3.Lame;
import org.apache.commons.math3.util.FastMath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import net.sourceforge.lame.lowlevel.LameEncoder;
import net.sourceforge.lame.mp3.Lame;
import org.apache.commons.math3.util.FastMath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Converts PCM audio packets to Mono, MP3 encoded audio
@@ -45,16 +45,20 @@ public class MP3AudioConverter implements IAudioConverter
private byte[] mOutputFramesBuffer;
private InputAudioFormat mInputAudioFormat;
private boolean mNormalizeAudio;
/**
* Constructs an instance.
*
* @param inputAudioFormat for the desired input sample rate and bit size (resampled from default 8 kHz as needed)
* @param setting to configure the LAME encoder
* @param normalizeAudio to normalize the audio gain prior to encoding
*/
public MP3AudioConverter(InputAudioFormat inputAudioFormat, MP3Setting setting)
public MP3AudioConverter(InputAudioFormat inputAudioFormat, MP3Setting setting, boolean normalizeAudio)
{
mInputAudioFormat = inputAudioFormat;
mEncoder = LameFactory.getLameEncoder(inputAudioFormat, setting);
mNormalizeAudio = normalizeAudio;
//Resampling is only required if desired input sample rate is not system default of 8kHz
if(inputAudioFormat != InputAudioFormat.SR_8000 && inputAudioFormat != InputAudioFormat.SR_32_8000)
@@ -74,6 +78,11 @@ public class MP3AudioConverter implements IAudioConverter
{
List<byte[]> converted = new ArrayList<>();
if(mNormalizeAudio)
{
audioPackets = AudioUtils.normalize(audioPackets);
}
if(mResampler != null)
{
audioPackets = mResampler.resample(audioPackets);

View File

@@ -34,8 +34,8 @@ public enum MP3Setting
CBR_16(false, 16, "CBR - Constant Bit Rate 16 kbps (default)"),
CBR_32(false, 32, "CBR - Constant Bit Rate 32 kbps"),
ABR_56(true, 56, "ABR - Average Bit Rate 56 kbps"),
VBR_5(true, Lame.QUALITY_MIDDLE, "VBR - Middle Quality (5)"),
VBR_7(true, Lame.QUALITY_LOW, "VBR - Low Quality (7)");
VBR_5(true, Lame.QUALITY_MIDDLE, "VBR - Variable Bit Rate - Better Quality"),
VBR_7(true, Lame.QUALITY_LOW, "VBR - Variable Bit Rate - Good Quality");
private boolean mVariableBitRate;
private int mSetting;

View File

@@ -18,11 +18,10 @@
*/
package io.github.dsheirer.audio.convert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MP3SilenceGenerator implements ISilenceGenerator
{
@@ -40,7 +39,7 @@ public class MP3SilenceGenerator implements ISilenceGenerator
public MP3SilenceGenerator(InputAudioFormat inputAudioFormat, MP3Setting setting)
{
mInputAudioFormat = inputAudioFormat;
mMP3AudioConverter = new MP3AudioConverter(inputAudioFormat, setting);
mMP3AudioConverter = new MP3AudioConverter(inputAudioFormat, setting, false);
}
/**

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 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/>
* * *****************************************************************************
* 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.audio.convert.thumbdv.message;

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 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/>
* * *****************************************************************************
* 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.audio.convert.thumbdv.message.response;

View File

@@ -1,7 +1,6 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2018 Dennis Sheirer
* *****************************************************************************
* Copyright (C) 2014-2022 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
@@ -15,7 +14,7 @@
*
* 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.audio.playback;
@@ -30,7 +29,6 @@ import io.github.dsheirer.icon.IconModel;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.settings.SettingsManager;
import io.github.dsheirer.source.SourceManager;
import io.github.dsheirer.source.mixer.MixerChannelConfiguration;
import jiconfont.icons.font_awesome.FontAwesome;
import jiconfont.swing.IconFontSwing;
@@ -69,7 +67,6 @@ public class AudioPanel extends JPanel implements Listener<AudioEvent>
private IconModel mIconModel;
private SettingsManager mSettingsManager;
private SourceManager mSourceManager;
private IAudioController mController;
private AliasModel mAliasModel;
private UserPreferences mUserPreferences;
@@ -78,11 +75,10 @@ public class AudioPanel extends JPanel implements Listener<AudioEvent>
private AudioChannelsPanel mAudioChannelsPanel;
public AudioPanel(IconModel iconModel, UserPreferences userPreferences, SettingsManager settingsManager,
SourceManager sourceManager, IAudioController controller, AliasModel aliasModel)
IAudioController controller, AliasModel aliasModel)
{
mIconModel = iconModel;
mSettingsManager = settingsManager;
mSourceManager = sourceManager;
mController = controller;
mAliasModel = aliasModel;
mUserPreferences = userPreferences;

View File

@@ -35,7 +35,7 @@ public class BinaryMessage extends BitSet
* Logical (ie constructed) size of this bitset, despite the actual size of
* the super bitset that this class is based on
*/
private int mSize = 0;
private int mSize;
/**
* Pointer to the next fill index location, when adding bits to this bitset
@@ -43,21 +43,21 @@ public class BinaryMessage extends BitSet
*/
private int mPointer = 0;
/**
* Bitset that buffers bits added one at a time, up to the size of the this
* bitset.
*
* Note: the super class bitset behind this class may have a size larger
* that the size parameter specified.
* @param size
*/
/**
* Used for temporary storage of CRC check results when we're passing this
* message to an EDAC function.
*/
private CRC mCRC;
/**
* Constructs a bitset that buffers bits added one at a time, up to the size
* of the this bitset.
* <p>
* Note: the super class bitset behind this class may have a size larger
* that the size parameter specified.
*
* @param size of constructed bitset
*/
public BinaryMessage(int size)
{
super(size);
@@ -214,9 +214,7 @@ public class BinaryMessage extends BitSet
}
/**
* Returns a (new) copy of this bitsetbuffer
*
* @return
* @return a (new) copy of this binary message
*/
public BinaryMessage copy()
{

View File

@@ -21,7 +21,6 @@ package io.github.dsheirer.buffer;
import io.github.dsheirer.sample.complex.ComplexSamples;
import io.github.dsheirer.sample.complex.InterleavedComplexSamples;
import java.util.Iterator;
/**
@@ -42,7 +41,7 @@ public class ByteNativeBuffer implements INativeBuffer
for(int x = 0; x < 256; x++)
{
LOOKUP_VALUES[x] = (float)(x - 127) / 128.0f;
LOOKUP_VALUES[x] = ((float)x - 127.5f) / 128.0f;
}
}

View File

@@ -26,16 +26,20 @@ import java.nio.ByteBuffer;
*/
public class ByteNativeBufferFactory implements INativeBufferFactory
{
private static final float DC_FILTER_GAIN = 0.007f; //Normalizes DC over period of ~142 (1 / .007) buffers
private float mAverageDc = 0.0f;
private DcCorrectionManager mDcCorrectionManager = new DcCorrectionManager();
@Override
public INativeBuffer getBuffer(ByteBuffer samples, long timestamp)
{
byte[] copy = new byte[samples.capacity()];
samples.get(copy);
calculateDc(copy);
return new ByteNativeBuffer(copy, timestamp, mAverageDc);
if(mDcCorrectionManager.shouldCalculateDc())
{
calculateDc(copy);
}
return new ByteNativeBuffer(copy, timestamp, mDcCorrectionManager.getAverageDc());
}
/**
@@ -45,7 +49,7 @@ public class ByteNativeBufferFactory implements INativeBufferFactory
*/
private void calculateDc(byte[] samples)
{
double dcAccumulator = 0;
float dcAccumulator = 0;
for(byte sample: samples)
{
@@ -53,9 +57,8 @@ public class ByteNativeBufferFactory implements INativeBufferFactory
}
dcAccumulator /= samples.length;
dcAccumulator -= 127.0f;
dcAccumulator -= 127.5f;
dcAccumulator /= 128.0f;
dcAccumulator -= mAverageDc;
mAverageDc += (dcAccumulator * DC_FILTER_GAIN);
mDcCorrectionManager.adjust(dcAccumulator);
}
}

View File

@@ -1,20 +1,21 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2018 Dennis Sheirer
/*
* *****************************************************************************
* Copyright (C) 2014-2022 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 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.
* 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/>
******************************************************************************/
* 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;
import io.github.dsheirer.sample.complex.Complex;

View File

@@ -0,0 +1,114 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 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;
import java.util.concurrent.TimeUnit;
/**
* Provides DC offset correction value and manages calculation processing interval.
*/
public class DcCorrectionManager
{
// private static Logger mLog = LoggerFactory.getLogger(DcCorrectionManager.class);
// private DecimalFormat mDecimalFormat = new DecimalFormat("0.00000");
/**
* Time (delay) interval for running DC removal calculations
*/
private static final long DC_PROCESSING_INTERVAL = TimeUnit.SECONDS.toMillis(50);
/**
* Number of buffers to process per DC calculation processing interval.
*/
private static final int DC_CALCULATIONS_PER_INTERVAL = 5;
/**
* DC offset processing residual threshold for ending DC processing interval
*/
private static final float TARGET_DC_OFFSET_REMAINING = 0.0001f;
/**
* Number of DC calculations remaining in the current interval
*/
private int mDcCalculationsRemaining = DC_CALCULATIONS_PER_INTERVAL; //Initial value for coarse correction
/**
* Last time DC offset calculation interval ran
*/
private long mLastDcCalculationTimestamp = 0;
/**
* DC offset calculation gain.
*/
private static final float DC_FILTER_GAIN = 0.05f;
/**
* Current DC offset correction value
*/
private float mAverageDc = 0.0f;
public float getAverageDc()
{
return mAverageDc;
}
/**
* Adjusts the average DC based on the current calculated DC offset present in a sample buffer.
* @param calculatedDc for the current sample buffer
*/
public void adjust(float calculatedDc)
{
//Calculate the average scaled DC offset so that it can be applied in the native buffer's converted samples
float residualOffsetToRemove = calculatedDc - mAverageDc;
mAverageDc += (residualOffsetToRemove * DC_FILTER_GAIN);
if(Math.abs(residualOffsetToRemove) < TARGET_DC_OFFSET_REMAINING)
{
mDcCalculationsRemaining--;
}
//
// mLog.info("DC: " + mDecimalFormat.format(mAverageDc) +
// " RES:" + mDecimalFormat.format(residualOffsetToRemove) +
// " REM:" + mDcCalculationsRemaining);
}
/**
* Indicates if a DC offset calculation for a buffer should be performed.
*/
public boolean shouldCalculateDc()
{
if(System.currentTimeMillis() > (mLastDcCalculationTimestamp + DC_PROCESSING_INTERVAL))
{
if(mDcCalculationsRemaining > 0)
{
return true;
}
else
{
//Reset the number of buffers to calculate and the timestamp
mDcCalculationsRemaining = DC_CALCULATIONS_PER_INTERVAL;
mLastDcCalculationTimestamp = System.currentTimeMillis();
}
}
return false;
}
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2021 Dennis Sheirer
* Copyright (C) 2014-2022 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

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2017 Dennis Sheirer
/*
* *****************************************************************************
* Copyright (C) 2014-2022 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
@@ -14,8 +14,8 @@
*
* 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;
/**

View File

@@ -20,14 +20,51 @@
package io.github.dsheirer.buffer;
import java.nio.ByteBuffer;
import java.util.concurrent.TimeUnit;
/**
* Implements a factory for creating SignedByteNativeBuffer instances
*/
public class SignedByteNativeBufferFactory implements INativeBufferFactory
{
private static final float DC_FILTER_GAIN = 0.02f; //Normalizes DC over period of ~50 (1 / .02) buffers
/**
* DC removal calculations will run once a minute
*/
private static final long DC_PROCESSING_INTERVAL = TimeUnit.SECONDS.toMillis(60);
/**
* Number of buffers to process per DC calculation processing interval.
*/
private static final int DC_CALCULATIONS_PER_INTERVAL = 5;
/**
* DC offset processing residual threshold for ending DC processing interval
*/
private static final float TARGET_DC_OFFSET_REMAINING = 0.0002f;
/**
* Number of DC calculations remaining in the current interval
*/
private int mDcCalculationsRemaining = DC_CALCULATIONS_PER_INTERVAL; //Initial value for coarse correction
/**
* Last time DC offset calculation interval ran
*/
private long mLastDcCalculationTimestamp = 0;
/**
* DC offset calculation gain.
*/
private static final float DC_FILTER_GAIN = 0.05f;
/**
* Current DC offset correction for Inphase samples
*/
private float mIAverageDc = 0.0f;
/**
* Current DC offset correction for Quadrature samples
*/
private float mQAverageDc = 0.0f;
@Override
@@ -35,10 +72,37 @@ public class SignedByteNativeBufferFactory implements INativeBufferFactory
{
byte[] copy = new byte[samples.capacity()];
samples.get(copy);
calculateDc(copy);
if(shouldCalculateDc())
{
calculateDc(copy);
}
return new SignedByteNativeBuffer(copy, timestamp, mIAverageDc, mQAverageDc);
}
/**
* Indicates if a DC offset calculation for a buffer should be performed.
*/
private boolean shouldCalculateDc()
{
if(System.currentTimeMillis() > (mLastDcCalculationTimestamp + DC_PROCESSING_INTERVAL))
{
if(mDcCalculationsRemaining > 0)
{
return true;
}
else
{
//Reset the number of buffers to calculate and the timestamp
mDcCalculationsRemaining = DC_CALCULATIONS_PER_INTERVAL;
mLastDcCalculationTimestamp = System.currentTimeMillis();
}
}
return false;
}
/**
* Calculates the average DC in the sample stream so that it can be subtracted from the samples when the
* native buffer is used.
@@ -46,8 +110,8 @@ public class SignedByteNativeBufferFactory implements INativeBufferFactory
*/
private void calculateDc(byte[] samples)
{
double iDcAccumulator = 0;
double qDcAccumulator = 0;
float iDcAccumulator = 0;
float qDcAccumulator = 0;
for(int x = 0; x < samples.length; x += 2)
{
@@ -64,5 +128,10 @@ public class SignedByteNativeBufferFactory implements INativeBufferFactory
qDcAccumulator /= 128.0f;
qDcAccumulator -= mQAverageDc;
mQAverageDc += (qDcAccumulator * DC_FILTER_GAIN);
if(Math.abs(iDcAccumulator) < TARGET_DC_OFFSET_REMAINING && Math.abs(qDcAccumulator) < TARGET_DC_OFFSET_REMAINING)
{
mDcCalculationsRemaining--;
}
}
}

View File

@@ -19,6 +19,7 @@
package io.github.dsheirer.buffer.airspy;
import io.github.dsheirer.buffer.DcCorrectionManager;
import java.nio.ByteBuffer;
/**
@@ -26,40 +27,61 @@ import java.nio.ByteBuffer;
*/
public class ScalarPackedSampleConverter implements IAirspySampleConverter
{
private static final float DC_FILTER_GAIN = 0.007f; //Normalizes DC over period of ~142 (1 / .007) buffers
private float mAverageDc = 0.0f;
/**
* Manages DC calculations and processing interval
*/
private DcCorrectionManager mDcCalculationManager = new DcCorrectionManager();
@Override
public short[] convert(ByteBuffer buffer)
{
boolean shouldCalculateDc = mDcCalculationManager.shouldCalculateDc();
int offset = 0;
long dcAccumulator = 0;
short sample;
short[] samples;
byte b1, b2, b3;
samples = new short[buffer.capacity() / 3 * 2];
for(int x = 0; x < samples.length; x += 2)
if(shouldCalculateDc)
{
b1 = buffer.get(offset++);
b2 = buffer.get(offset++);
b3 = buffer.get(offset++);
long dcAccumulator = 0;
sample = (short)(((b1 & 0xFF) << 4) | ((b2 & 0xF0) >> 4));
samples[x] = sample;
dcAccumulator += sample;
for(int x = 0; x < samples.length; x += 2)
{
b1 = buffer.get(offset++);
b2 = buffer.get(offset++);
b3 = buffer.get(offset++);
sample = (short)(((b2 & 0xF) << 8) | (b3 & 0xFF));
samples[x] = sample;
dcAccumulator += sample;
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 *= AirspyBufferIterator.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++);
//Calculate the average scaled DC offset so that it can be applied in the native buffer's converted samples
float averageDcNow = ((float)dcAccumulator / (float)samples.length) - 2048.0f;
averageDcNow *= AirspyBufferIterator.SCALE_SIGNED_12_BIT_TO_FLOAT;
averageDcNow -= mAverageDc;
mAverageDc += (averageDcNow * DC_FILTER_GAIN);
sample = (short)(((b1 & 0xFF) << 4) | ((b2 & 0xF0) >> 4));
samples[x] = sample;
sample = (short)(((b2 & 0xF) << 8) | (b3 & 0xFF));
samples[x] = sample;
}
}
return samples;
}
@@ -67,7 +89,7 @@ public class ScalarPackedSampleConverter implements IAirspySampleConverter
@Override
public float getAverageDc()
{
return mAverageDc;
return mDcCalculationManager.getAverageDc();
}
public static void main(String[] args)

View File

@@ -19,6 +19,7 @@
package io.github.dsheirer.buffer.airspy;
import io.github.dsheirer.buffer.DcCorrectionManager;
import java.nio.ByteBuffer;
/**
@@ -26,34 +27,50 @@ import java.nio.ByteBuffer;
*/
public class ScalarUnpackedSampleConverter implements IAirspySampleConverter
{
private static final float DC_FILTER_GAIN = 0.007f; //Normalizes DC over period of ~142 (1 / .007) buffers
private float mAverageDc = 0.0f;
/**
* Manages DC calculations and processing interval
*/
private DcCorrectionManager mDcCalculationManager = new DcCorrectionManager();
@Override
public short[] convert(ByteBuffer buffer)
{
boolean shouldCalculateDc = mDcCalculationManager.shouldCalculateDc();
int offset = 0;
long dcAccumulator = 0;
short sample;
short[] samples;
byte b1, b2;
samples = new short[buffer.capacity() / 2];
for(int x = 0; x < samples.length; x++)
if(shouldCalculateDc)
{
b1 = buffer.get(offset++);
b2 = buffer.get(offset++);
sample = (short)(((b2 & 0x0F) << 8) | (b1 & 0xFF));
samples[x] = sample;
dcAccumulator += sample;
}
long dcAccumulator = 0;
//Calculate the average scaled DC offset so that it can be applied in the native buffer's converted samples
float averageDcNow = ((float)dcAccumulator / (float)samples.length) - 2048.0f;
averageDcNow *= AirspyBufferIterator.SCALE_SIGNED_12_BIT_TO_FLOAT;
averageDcNow -= mAverageDc;
mAverageDc += (averageDcNow * DC_FILTER_GAIN);
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 *= AirspyBufferIterator.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;
}
@@ -61,6 +78,6 @@ public class ScalarUnpackedSampleConverter implements IAirspySampleConverter
@Override
public float getAverageDc()
{
return mAverageDc;
return mDcCalculationManager.getAverageDc();
}
}

View File

@@ -19,25 +19,29 @@
package io.github.dsheirer.buffer.airspy;
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;
import java.nio.ByteBuffer;
/**
* Scalar implementation of airspy sample converter for un-packed samples.
*/
public class VectorUnpackedSampleConverter implements IAirspySampleConverter
{
private static final VectorSpecies<Short> VECTOR_SPECIES = ShortVector.SPECIES_PREFERRED;
private static final float DC_FILTER_GAIN = 0.007f; //Normalizes DC over period of ~142 (1 / .007) buffers
private float mAverageDc = 0.0f;
/**
* Manages DC calculations and processing interval
*/
private DcCorrectionManager mDcCalculationManager = new DcCorrectionManager();
@Override
public short[] convert(ByteBuffer buffer)
{
long dcAccumulator = 0;
boolean shouldCalculateDc = mDcCalculationManager.shouldCalculateDc();
short sample;
short[] samples;
byte b1, b2;
@@ -53,44 +57,73 @@ public class VectorUnpackedSampleConverter implements IAirspySampleConverter
short[] bytes1 = new short[VECTOR_SPECIES.length()];
short[] bytes2 = new short[VECTOR_SPECIES.length()];
for(; samplesOffset < VECTOR_SPECIES.loopBound(samples.length); samplesOffset += VECTOR_SPECIES.length())
if(shouldCalculateDc)
{
bytesOffset = 0;
long dcAccumulator = 0;
while(bytesOffset < VECTOR_SPECIES.length())
for(; samplesOffset < VECTOR_SPECIES.loopBound(samples.length); samplesOffset += VECTOR_SPECIES.length())
{
bytes1[bytesOffset] = (short)(buffer.get(rawPointer++) & 0xFF);
bytes2[bytesOffset++] = (short)(buffer.get(rawPointer++) & 0x0F);
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);
}
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++);
for(; samplesOffset < samples.length; samplesOffset++)
sample = (short)(((b2 & 0x0F) << 8) | (b1 & 0xFF));
samples[samplesOffset] = sample;
dcAccumulator += sample;
}
float averageDcNow = ((float)dcAccumulator / (float)samples.length) - 2048.0f;
averageDcNow *= AirspyBufferIterator.SCALE_SIGNED_12_BIT_TO_FLOAT;
mDcCalculationManager.adjust(averageDcNow);
}
else
{
b1 = buffer.get(rawPointer++);
b2 = buffer.get(rawPointer++);
for(; samplesOffset < VECTOR_SPECIES.loopBound(samples.length); samplesOffset += VECTOR_SPECIES.length())
{
bytesOffset = 0;
sample = (short)(((b2 & 0x0F) << 8) | (b1 & 0xFF));
samples[samplesOffset] = sample;
dcAccumulator += sample;
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;
}
}
//Calculate the average scaled DC offset so that it can be applied in the native buffer's converted samples
float averageDcNow = ((float)dcAccumulator / (float)samples.length) - 2048.0f;
averageDcNow *= AirspyBufferIterator.SCALE_SIGNED_12_BIT_TO_FLOAT;
averageDcNow -= mAverageDc;
mAverageDc += (averageDcNow * DC_FILTER_GAIN);
return samples;
}
@Override
public float getAverageDc()
{
return mAverageDc;
return mDcCalculationManager.getAverageDc();
}
}

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 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/>
* * *****************************************************************************
* 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.channel.metadata;

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 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/>
* * *****************************************************************************
* 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.channel.state;

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 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/>
* * *****************************************************************************
* 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.channel.state;

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 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/>
* * *****************************************************************************
* 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.channel.state;

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 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/>
* * *****************************************************************************
* 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.channel.state;

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 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/>
* * *****************************************************************************
* 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.channel.state;

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer
* Copyright (C) 2014-2022 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
@@ -30,8 +30,8 @@ import io.github.dsheirer.map.MapService;
import io.github.dsheirer.playlist.PlaylistManager;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.settings.SettingsManager;
import io.github.dsheirer.source.SourceManager;
import io.github.dsheirer.source.tuner.TunerViewPanel;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import io.github.dsheirer.source.tuner.ui.TunerViewPanel;
import jiconfont.icons.font_awesome.FontAwesome;
import jiconfont.swing.IconFontSwing;
import net.miginfocom.swing.MigLayout;
@@ -59,13 +59,13 @@ public class ControllerPanel extends JPanel
public ControllerPanel(PlaylistManager playlistManager, AudioPlaybackManager audioPlaybackManager,
IconModel iconModel, MapService mapService, SettingsManager settingsManager,
SourceManager sourceManager, UserPreferences userPreferences)
TunerManager tunerManager, UserPreferences userPreferences)
{
mAudioPanel = new AudioPanel(iconModel, userPreferences, settingsManager, sourceManager, audioPlaybackManager,
mAudioPanel = new AudioPanel(iconModel, userPreferences, settingsManager, audioPlaybackManager,
playlistManager.getAliasModel());
mNowPlayingPanel = new NowPlayingPanel(playlistManager, iconModel, userPreferences);
mMapPanel = new MapPanel(mapService, playlistManager.getAliasModel(), iconModel, settingsManager);
mTunerManagerPanel = new TunerViewPanel(sourceManager.getTunerModel(), userPreferences);
mTunerManagerPanel = new TunerViewPanel(tunerManager, userPreferences);
init();
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer
* Copyright (C) 2014-2022 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

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 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/>
* * *****************************************************************************
* 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.controller.channel;
@@ -28,6 +25,7 @@ import io.github.dsheirer.channel.metadata.ChannelAndMetadata;
import io.github.dsheirer.channel.metadata.ChannelMetadata;
import io.github.dsheirer.channel.metadata.ChannelMetadataModel;
import io.github.dsheirer.controller.channel.event.ChannelStartProcessingRequest;
import io.github.dsheirer.controller.channel.event.ChannelStopProcessingRequest;
import io.github.dsheirer.controller.channel.event.PreloadDataContent;
import io.github.dsheirer.controller.channel.map.ChannelMapModel;
import io.github.dsheirer.identifier.Form;
@@ -47,14 +45,12 @@ import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.source.Source;
import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.SourceException;
import io.github.dsheirer.source.SourceManager;
import io.github.dsheirer.source.config.SourceConfigTuner;
import io.github.dsheirer.source.config.SourceConfigTunerMultipleFrequency;
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import io.github.dsheirer.util.ThreadPool;
import javafx.application.Platform;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.GraphicsEnvironment;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -64,6 +60,9 @@ import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javafx.application.Platform;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Channel processing manager handles all starting and stopping of channel decoding. A processing chain is created
@@ -86,7 +85,7 @@ public class ChannelProcessingManager implements Listener<ChannelEvent>
private ChannelMapModel mChannelMapModel;
private ChannelMetadataModel mChannelMetadataModel;
private EventLogManager mEventLogManager;
private SourceManager mSourceManager;
private TunerManager mTunerManager;
private AliasModel mAliasModel;
private UserPreferences mUserPreferences;
private List<Long> mLoggedFrequencies = new ArrayList<>();
@@ -97,16 +96,16 @@ public class ChannelProcessingManager implements Listener<ChannelEvent>
*
* @param channelMapModel containing channel maps defined by the user
* @param eventLogManager for adding event loggers to channels
* @param sourceManager for obtaining a tuner channel source for the channel
* @param tunerManager for obtaining a tuner channel source for the channel
* @param aliasModel for aliasing of identifiers produced by the channel
* @param userPreferences for user defined behavior and settings
*/
public ChannelProcessingManager(ChannelMapModel channelMapModel, EventLogManager eventLogManager,
SourceManager sourceManager, AliasModel aliasModel, UserPreferences userPreferences)
TunerManager tunerManager, AliasModel aliasModel, UserPreferences userPreferences)
{
mChannelMapModel = channelMapModel;
mEventLogManager = eventLogManager;
mSourceManager = sourceManager;
mTunerManager = tunerManager;
mAliasModel = aliasModel;
mUserPreferences = userPreferences;
mChannelMetadataModel = new ChannelMetadataModel();
@@ -126,7 +125,20 @@ public class ChannelProcessingManager implements Listener<ChannelEvent>
*/
private boolean isProcessing(Channel channel)
{
return mProcessingChains.containsKey(channel) && mProcessingChains.get(channel).isProcessing();
boolean isProcessing = false;
mLock.lock();
try
{
isProcessing = mProcessingChains.containsKey(channel) && mProcessingChains.get(channel).isProcessing();
}
finally
{
mLock.unlock();
}
return isProcessing;
}
/**
@@ -155,18 +167,60 @@ public class ChannelProcessingManager implements Listener<ChannelEvent>
*/
public Channel getChannel(ProcessingChain processingChain)
{
Channel channel = null;
if(processingChain != null)
{
for(Map.Entry<Channel,ProcessingChain> entry : mProcessingChains.entrySet())
mLock.lock();
try
{
if(entry.getValue() == processingChain)
for(Map.Entry<Channel,ProcessingChain> entry : mProcessingChains.entrySet())
{
return entry.getKey();
if(entry.getValue() == processingChain)
{
channel = entry.getKey();
break;
}
}
}
finally
{
mLock.unlock();
}
}
return null;
return channel;
}
/**
* Retrieves the channel associated with the processing chain that is consuming from the tuner channel source
* @param tunerChannelSource to find the channel
* @return channel
*/
private Channel getChannel(TunerChannelSource tunerChannelSource)
{
Channel channel = null;
mLock.lock();
try
{
for(Map.Entry<Channel,ProcessingChain> entry : mProcessingChains.entrySet())
{
if(entry.getValue().hasSource(tunerChannelSource))
{
channel = entry.getKey();
break;
}
}
}
finally
{
mLock.unlock();
}
return channel;
}
/**
@@ -275,6 +329,28 @@ public class ChannelProcessingManager implements Listener<ChannelEvent>
}
}
/**
* Request to stop a channel that is currently processing
* @param request with the tuner channel source feeding the channel to be stopped.
*/
@Subscribe
public void stopChannelRequest(ChannelStopProcessingRequest request)
{
Channel channel = getChannel(request.getTunerChannelSource());
if(channel != null)
{
try
{
stop(channel);
}
catch(ChannelException ce)
{
mLog.error("Error stopping channel [" + channel + "]", ce);
}
}
}
/**
* Stops the specified channel
* @param channel to stop
@@ -303,7 +379,7 @@ public class ChannelProcessingManager implements Listener<ChannelEvent>
try
{
source = mSourceManager.getSource(channel.getSourceConfiguration(),
source = mTunerManager.getSource(channel.getSourceConfiguration(),
channel.getDecodeConfiguration().getChannelSpecification());
}
catch(SourceException se)
@@ -439,8 +515,15 @@ public class ChannelProcessingManager implements Listener<ChannelEvent>
{
processingChain.start();
//This has to be done on the FX event thread when the playlist editor is constructed
Platform.runLater(() -> channel.setProcessing(true));
if(GraphicsEnvironment.isHeadless())
{
channel.setProcessing(true);
}
else
{
//This has to be done on the FX event thread when the playlist editor is constructed
Platform.runLater(() -> channel.setProcessing(true));
}
mChannelEventBroadcaster.broadcast(new ChannelEvent(channel, ChannelEvent.Event.NOTIFICATION_PROCESSING_START));
}
@@ -526,13 +609,20 @@ public class ChannelProcessingManager implements Listener<ChannelEvent>
*/
private void stopProcessing(Channel channel) throws ChannelException
{
//This has to be done on the FX event thread when the playlist editor is constructed
Platform.runLater(() -> channel.setProcessing(false));
ProcessingChain processingChain = removeProcessingChain(channel);
if(processingChain != null)
{
if(GraphicsEnvironment.isHeadless())
{
channel.setProcessing(false);
}
else
{
//This has to be done on the FX event thread when the playlist editor is constructed
Platform.runLater(() -> channel.setProcessing(false));
}
//Since the processing chain's source will block on stop(), throw it to the thread pool to run
ThreadPool.CACHED.submit(() -> {
try
@@ -558,10 +648,6 @@ public class ChannelProcessingManager implements Listener<ChannelEvent>
}
});
}
else
{
throw new ChannelException("Channel is not currently playing");
}
}
/**
@@ -736,7 +822,14 @@ public class ChannelProcessingManager implements Listener<ChannelEvent>
if(toShutdown != null)
{
mLog.warn("Channel source error detected - stopping channel [" + toShutdown.getName() + "]");
if(sourceEvent.getEvent() == SourceEvent.Event.NOTIFICATION_ERROR_STATE)
{
mLog.warn("Channel source error detected - stopping channel [" + toShutdown.getName() + "]");
}
else
{
mLog.warn("Source event error - stopping channel [" + toShutdown.getName() + "]");
}
try
{

View File

@@ -0,0 +1,44 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 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.controller.channel.event;
import io.github.dsheirer.module.ModuleEventBusMessage;
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
/**
* Request to stop processing a channel for a specific tuner channel source
*/
public class ChannelStopProcessingRequest extends ModuleEventBusMessage
{
private TunerChannelSource mTunerChannelSource;
/**
* Constructs an instance
* @param tunerChannelSource for the channel to stop
*/
public ChannelStopProcessingRequest(TunerChannelSource tunerChannelSource)
{
mTunerChannelSource = tunerChannelSource;
}
public TunerChannelSource getTunerChannelSource()
{
return mTunerChannelSource;
}
}

View File

@@ -21,11 +21,13 @@ package io.github.dsheirer.dsp.filter.channelizer;
import io.github.dsheirer.buffer.INativeBuffer;
import io.github.dsheirer.buffer.INativeBufferProvider;
import io.github.dsheirer.buffer.NativeBufferPoisonPill;
import io.github.dsheirer.controller.channel.event.ChannelStopProcessingRequest;
import io.github.dsheirer.dsp.filter.FilterFactory;
import io.github.dsheirer.dsp.filter.channelizer.output.IPolyphaseChannelOutputProcessor;
import io.github.dsheirer.dsp.filter.channelizer.output.OneChannelOutputProcessor;
import io.github.dsheirer.dsp.filter.channelizer.output.TwoChannelOutputProcessor;
import io.github.dsheirer.dsp.filter.design.FilterDesignException;
import io.github.dsheirer.eventbus.MyEventBus;
import io.github.dsheirer.sample.Broadcaster;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.complex.InterleavedComplexSamples;
@@ -37,10 +39,7 @@ import io.github.dsheirer.source.tuner.TunerController;
import io.github.dsheirer.source.tuner.channel.TunerChannel;
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
import io.github.dsheirer.util.Dispatcher;
import org.apache.commons.math3.util.FastMath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -50,6 +49,9 @@ import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import org.apache.commons.math3.util.FastMath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Polyphase Channel Manager is a DDC channel manager and complex buffer queue/processor for a tuner. This class
@@ -84,6 +86,7 @@ public class PolyphaseChannelManager implements ISourceEventProcessor
private NativeBufferReceiver mNativeBufferReceiver = new NativeBufferReceiver();
private Dispatcher mBufferDispatcher;
private Map<Integer,float[]> mOutputProcessorFilters = new HashMap<>();
private boolean mRunning = true;
/**
* Creates a polyphase channel manager instance.
@@ -126,6 +129,18 @@ public class PolyphaseChannelManager implements ISourceEventProcessor
this(tunerController, tunerController.getFrequency(), tunerController.getSampleRate());
}
public void stopAllChannels()
{
mRunning = false;
List<TunerChannelSource> toStop = new ArrayList<>(mChannelSources);
for(TunerChannelSource tunerChannelSource: toStop)
{
MyEventBus.getGlobalEventBus().post(new ChannelStopProcessingRequest(tunerChannelSource));
}
}
/**
* Signals to all provisioned tuner channel sources that the source complex buffer provider has an error and can
* no longer provide channels, so that the tuner channel source can notify the consumer of the error state.
@@ -164,24 +179,27 @@ public class PolyphaseChannelManager implements ISourceEventProcessor
{
PolyphaseChannelSource channelSource = null;
List<Integer> polyphaseIndexes = mChannelCalculator.getChannelIndexes(tunerChannel);
IPolyphaseChannelOutputProcessor outputProcessor = getOutputProcessor(polyphaseIndexes);
if(outputProcessor != null)
if(mRunning)
{
long centerFrequency = mChannelCalculator.getCenterFrequencyForIndexes(polyphaseIndexes);
List<Integer> polyphaseIndexes = mChannelCalculator.getChannelIndexes(tunerChannel);
try
{
channelSource = new PolyphaseChannelSource(tunerChannel, outputProcessor, mChannelSourceEventListener,
mChannelCalculator.getChannelSampleRate(), centerFrequency);
IPolyphaseChannelOutputProcessor outputProcessor = getOutputProcessor(polyphaseIndexes);
mChannelSources.add(channelSource);
}
catch(FilterDesignException fde)
if(outputProcessor != null)
{
mLog.debug("Couldn't design final output low pass filter for polyphase channel source");
long centerFrequency = mChannelCalculator.getCenterFrequencyForIndexes(polyphaseIndexes);
try
{
channelSource = new PolyphaseChannelSource(tunerChannel, outputProcessor, mChannelSourceEventListener,
mChannelCalculator.getChannelSampleRate(), centerFrequency);
mChannelSources.add(channelSource);
}
catch(FilterDesignException fde)
{
mLog.debug("Couldn't design final output low pass filter for polyphase channel source");
}
}
}

View File

@@ -76,7 +76,7 @@ public class DecimationFilterFactory
*/
public static int getDecimationRate(int requestedRate)
{
if(requestedRate < 2)
if(requestedRate < 0)
{
throw new IllegalArgumentException("Requested decimation rate must be greater than 2");
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2021 Dennis Sheirer
* Copyright (C) 2014-2022 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

View File

@@ -1,3 +1,22 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 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.dsp.filter.fir.remez;
import io.github.dsheirer.dsp.filter.design.FilterDesignException;

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2017 Dennis Sheirer
/*
* *****************************************************************************
* Copyright (C) 2014-2022 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
@@ -14,8 +14,8 @@
*
* 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.dsp.filter.fir.remez;
import io.github.dsheirer.dsp.filter.design.FilterDesignException;

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2017 Dennis Sheirer
/*
* *****************************************************************************
* Copyright (C) 2014-2022 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
@@ -14,8 +14,8 @@
*
* 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.dsp.filter.fir.remez;
import io.github.dsheirer.dsp.filter.design.FilterDesignException;

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2021 Dennis Sheirer
* Copyright (C) 2014-2022 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

View File

@@ -1,20 +1,21 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
/*
* *****************************************************************************
* Copyright (C) 2014-2022 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 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.
* 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/>
******************************************************************************/
* 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.edac;
import io.github.dsheirer.bits.BinaryMessage;

View File

@@ -75,7 +75,7 @@ public class FilterEditorPanel<T> extends JPanel
List<IFilter<T>> filters = filterSet.getFilters();
/* sort the filters in alphabetical order by name */
filters.sort((Comparator<IFilter<?>>) (first, second) -> first.getName().compareTo(second.getName()));
filters.sort(Comparator.comparing(IFilter::getName));
for(IFilter<T> filter : filters)
{
@@ -98,7 +98,7 @@ public class FilterEditorPanel<T> extends JPanel
{
List<FilterElement<?>> elements = filter.getFilterElements();
elements.sort(Comparator.comparing(FilterElement::toString));
elements.sort(Comparator.comparing(FilterElement::getName));
for(FilterElement<?> element : elements)
{

View File

@@ -46,13 +46,14 @@ public class FilterSet<T> implements IFilter<T>
{
for( IFilter<T> filter: mFilters )
{
if( filter.canProcess( t ) )
// Make sure to loop through all filters.
// Only return if true or all filters have been evaluated.
if( filter.canProcess( t ) && filter.passes( t ))
{
return filter.passes( t );
return true;
}
}
}
return false;
}

View File

@@ -41,10 +41,7 @@ import io.github.dsheirer.jmbe.JmbeEditorRequest;
import io.github.dsheirer.module.log.EventLogManager;
import io.github.dsheirer.playlist.PlaylistManager;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.settings.SettingsManager;
import io.github.dsheirer.source.SourceManager;
import io.github.dsheirer.source.tuner.TunerModel;
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
@@ -79,6 +76,7 @@ public class JavaFxWindowManager extends Application
private JmbeEditor mJmbeEditor;
private PlaylistEditor mPlaylistEditor;
private PlaylistManager mPlaylistManager;
private TunerManager mTunerManager;
private UserPreferences mUserPreferences;
private UserPreferencesEditor mUserPreferencesEditor;
@@ -91,9 +89,10 @@ public class JavaFxWindowManager extends Application
/**
* Constructs an instance. Note: this constructor is used for Swing applications.
*/
public JavaFxWindowManager(UserPreferences userPreferences, PlaylistManager playlistManager)
public JavaFxWindowManager(UserPreferences userPreferences, TunerManager tunerManager, PlaylistManager playlistManager)
{
mUserPreferences = userPreferences;
mTunerManager = tunerManager;
mPlaylistManager = playlistManager;
setup();
@@ -106,12 +105,10 @@ public class JavaFxWindowManager extends Application
{
mUserPreferences = new UserPreferences();
AliasModel aliasModel = new AliasModel();
TunerConfigurationModel tunerConfigurationModel = new TunerConfigurationModel();
TunerModel tunerModel = new TunerModel(tunerConfigurationModel);
SourceManager sourceManager = new SourceManager(tunerModel, new SettingsManager(tunerConfigurationModel),
mUserPreferences);
EventLogManager eventLogManager = new EventLogManager(aliasModel, mUserPreferences);
mPlaylistManager = new PlaylistManager(mUserPreferences, sourceManager, aliasModel, eventLogManager, new IconModel());
mTunerManager = new TunerManager(mUserPreferences);
mTunerManager.start();
mPlaylistManager = new PlaylistManager(mUserPreferences, mTunerManager, aliasModel, eventLogManager, new IconModel());
mPlaylistManager.init();
setup();
}
@@ -274,7 +271,7 @@ public class JavaFxWindowManager extends Application
{
if(mPlaylistEditor == null)
{
mPlaylistEditor = new PlaylistEditor(mPlaylistManager, mUserPreferences);
mPlaylistEditor = new PlaylistEditor(mPlaylistManager, mTunerManager, mUserPreferences);
}
return mPlaylistEditor;

View File

@@ -29,6 +29,7 @@ import io.github.dsheirer.audio.playback.AudioPlaybackManager;
import io.github.dsheirer.controller.ControllerPanel;
import io.github.dsheirer.controller.channel.Channel;
import io.github.dsheirer.controller.channel.ChannelAutoStartFrame;
import io.github.dsheirer.controller.channel.ChannelException;
import io.github.dsheirer.controller.channel.ChannelSelectionManager;
import io.github.dsheirer.eventbus.MyEventBus;
import io.github.dsheirer.gui.icon.ViewIconManagerRequest;
@@ -47,12 +48,11 @@ import io.github.dsheirer.properties.SystemProperties;
import io.github.dsheirer.record.AudioRecordingManager;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.settings.SettingsManager;
import io.github.dsheirer.source.SourceManager;
import io.github.dsheirer.source.tuner.Tuner;
import io.github.dsheirer.source.tuner.TunerEvent;
import io.github.dsheirer.source.tuner.TunerModel;
import io.github.dsheirer.source.tuner.TunerSpectralDisplayManager;
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
import io.github.dsheirer.source.tuner.manager.DiscoveredTuner;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import io.github.dsheirer.source.tuner.ui.TunerSpectralDisplayManager;
import io.github.dsheirer.spectrum.ClearTunerMenuItem;
import io.github.dsheirer.spectrum.ShowTunerMenuItem;
import io.github.dsheirer.spectrum.SpectralDisplayPanel;
@@ -68,11 +68,25 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JSeparator;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;
import javax.swing.plaf.metal.MetalLookAndFeel;
import java.awt.*;
import java.awt.AWTException;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
@@ -104,19 +118,24 @@ public class SDRTrunk implements Listener<TunerEvent>
private ControllerPanel mControllerPanel;
private IconModel mIconModel = new IconModel();
private PlaylistManager mPlaylistManager;
private SourceManager mSourceManager;
private SettingsManager mSettingsManager;
private SpectralDisplayPanel mSpectralPanel;
private JFrame mMainGui = new JFrame();
private JFrame mMainGui;
private JideSplitPane mSplitPane;
private JavaFxWindowManager mJavaFxWindowManager;
private UserPreferences mUserPreferences = new UserPreferences();
private TunerManager mTunerManager;
private ApplicationLog mApplicationLog;
private String mTitle;
public SDRTrunk()
{
if(!GraphicsEnvironment.isHeadless())
{
mMainGui = new JFrame();
}
mApplicationLog = new ApplicationLog(mUserPreferences);
mApplicationLog.start();
@@ -154,16 +173,19 @@ public class SDRTrunk implements Listener<TunerEvent>
//Register FontAwesome so we can use the fonts in Swing windows
IconFontSwing.register(FontAwesome.getIconFont());
TunerConfigurationModel tunerConfigurationModel = new TunerConfigurationModel();
TunerModel tunerModel = new TunerModel(tunerConfigurationModel);
mTunerManager = new TunerManager(mUserPreferences);
mTunerManager.start();
mSettingsManager = new SettingsManager(tunerConfigurationModel);
mSourceManager = new SourceManager(tunerModel, mSettingsManager, mUserPreferences);
mSettingsManager = new SettingsManager();
AliasModel aliasModel = new AliasModel();
EventLogManager eventLogManager = new EventLogManager(aliasModel, mUserPreferences);
mPlaylistManager = new PlaylistManager(mUserPreferences, mSourceManager, aliasModel, eventLogManager, mIconModel);
mJavaFxWindowManager = new JavaFxWindowManager(mUserPreferences, mPlaylistManager);
mPlaylistManager = new PlaylistManager(mUserPreferences, mTunerManager, aliasModel, eventLogManager, mIconModel);
if(!GraphicsEnvironment.isHeadless())
{
mJavaFxWindowManager = new JavaFxWindowManager(mUserPreferences, mTunerManager, mPlaylistManager);
}
CalibrationManager calibrationManager = CalibrationManager.getInstance(mUserPreferences);
final boolean calibrating = !calibrationManager.isCalibrated() &&
@@ -190,32 +212,45 @@ public class SDRTrunk implements Listener<TunerEvent>
MapService mapService = new MapService(mIconModel);
mPlaylistManager.getChannelProcessingManager().addDecodeEventListener(mapService);
mControllerPanel = new ControllerPanel(mPlaylistManager, audioPlaybackManager, mIconModel, mapService,
mSettingsManager, mSourceManager, mUserPreferences);
if(!GraphicsEnvironment.isHeadless())
{
mControllerPanel = new ControllerPanel(mPlaylistManager, audioPlaybackManager, mIconModel, mapService,
mSettingsManager, mTunerManager, mUserPreferences);
}
mSpectralPanel = new SpectralDisplayPanel(mPlaylistManager, mSettingsManager, tunerModel);
mSpectralPanel = new SpectralDisplayPanel(mPlaylistManager, mSettingsManager, mTunerManager.getDiscoveredTunerModel());
TunerSpectralDisplayManager tunerSpectralDisplayManager = new TunerSpectralDisplayManager(mSpectralPanel,
mPlaylistManager, mSettingsManager, tunerModel);
tunerModel.addListener(tunerSpectralDisplayManager);
tunerModel.addListener(this);
mPlaylistManager, mSettingsManager, mTunerManager.getDiscoveredTunerModel());
mTunerManager.getDiscoveredTunerModel().addListener(tunerSpectralDisplayManager);
mTunerManager.getDiscoveredTunerModel().addListener(this);
mPlaylistManager.init();
mLog.info("starting main application gui");
if(GraphicsEnvironment.isHeadless())
{
mLog.info("starting main application headless");
}
else
{
mLog.info("starting main application gui");
//Initialize the GUI
initGUI();
tunerModel.requestFirstTunerDisplay();
//Initialize the GUI
initGUI();
}
//Start the gui
EventQueue.invokeLater(() -> {
try
{
mMainGui.setVisible(true);
if(!GraphicsEnvironment.isHeadless())
{
mMainGui.setVisible(true);
Tuner tuner = tunerSpectralDisplayManager.showFirstTuner();
updateTitle(tuner);
}
if(calibrating)
if(calibrating && !GraphicsEnvironment.isHeadless())
{
Platform.runLater(() ->
{
@@ -256,8 +291,25 @@ public class SDRTrunk implements Listener<TunerEvent>
if(channels.size() > 0)
{
ChannelAutoStartFrame autoStartFrame = new ChannelAutoStartFrame(mPlaylistManager.getChannelProcessingManager(),
channels);
if(GraphicsEnvironment.isHeadless())
{
for(Channel channel: channels)
{
try
{
mLog.info("Auto-starting channel " + channel.getName());
mPlaylistManager.getChannelProcessingManager().start(channel);
}
catch(ChannelException ce)
{
mLog.error("Channel: " + channel.getName() + " auto-start failed: " + ce.getMessage());
}
}
}
else
{
new ChannelAutoStartFrame(mPlaylistManager.getChannelProcessingManager(), channels);
}
}
}
@@ -455,7 +507,8 @@ public class SDRTrunk implements Listener<TunerEvent>
mLog.info("Stopping spectral display ...");
mSpectralPanel.clearTuner();
mSourceManager.shutdown();
mLog.info("Stopping tuners ...");
mTunerManager.stop();
mLog.info("Shutdown complete.");
mApplicationLog.stop();
}
@@ -572,7 +625,23 @@ public class SDRTrunk implements Listener<TunerEvent>
{
if(event.getEvent() == TunerEvent.Event.REQUEST_MAIN_SPECTRAL_DISPLAY)
{
mMainGui.setTitle(mTitle + " - " + event.getTuner().getName());
updateTitle(event.getTuner());
}
}
/**
* Updates the title bar with the tuner name
* @param tuner optional
*/
private void updateTitle(Tuner tuner)
{
if(tuner != null)
{
mMainGui.setTitle(mTitle + " - " + tuner.getPreferredName());
}
else
{
mMainGui.setTitle(mTitle);
}
}
@@ -622,9 +691,9 @@ public class SDRTrunk implements Listener<TunerEvent>
{
removeAll();
for(Tuner tuner : mSourceManager.getTunerModel().getTuners())
for(DiscoveredTuner discoveredTuner: mTunerManager.getAvailableTuners())
{
add(new ShowTunerMenuItem(mSourceManager.getTunerModel(), tuner));
add(new ShowTunerMenuItem(mTunerManager.getDiscoveredTunerModel(), discoveredTuner.getTuner()));
}
}

View File

@@ -20,17 +20,16 @@ package io.github.dsheirer.gui.channelizer;
import io.github.dsheirer.buffer.FloatNativeBuffer;
import io.github.dsheirer.buffer.INativeBuffer;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.complex.ComplexSamples;
import io.github.dsheirer.settings.SettingsManager;
import io.github.dsheirer.source.ISourceEventProcessor;
import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.SourceException;
import io.github.dsheirer.source.tuner.LoggingTunerErrorListener;
import io.github.dsheirer.source.tuner.Tuner;
import io.github.dsheirer.source.tuner.channel.TunerChannel;
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
import io.github.dsheirer.source.tuner.test.TestTuner;
import io.github.dsheirer.spectrum.ComplexDftProcessor;
import io.github.dsheirer.spectrum.DFTSize;
@@ -40,10 +39,16 @@ import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JToggleButton;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
@@ -57,7 +62,7 @@ public class ChannelizerViewer extends JFrame
private static final int CHANNEL_BANDWIDTH = 12500;
private static final int CHANNEL_FFT_FRAME_RATE = 20;
private SettingsManager mSettingsManager = new SettingsManager(new TunerConfigurationModel());
private SettingsManager mSettingsManager = new SettingsManager();
private JPanel mPrimaryPanel;
private JPanel mControlPanel;
private JLabel mToneFrequencyLabel;
@@ -78,7 +83,7 @@ public class ChannelizerViewer extends JFrame
*/
public ChannelizerViewer(int channelsPerRow)
{
mTestTuner = new TestTuner(new UserPreferences());
mTestTuner = new TestTuner(new LoggingTunerErrorListener());
mChannelCount = (int)(mTestTuner.getTunerController().getBandwidth() / CHANNEL_BANDWIDTH);
mChannelsPerRow = channelsPerRow;
@@ -518,7 +523,7 @@ public class ChannelizerViewer extends JFrame
}
else
{
TestTuner tuner = new TestTuner(new UserPreferences());
TestTuner tuner = new TestTuner(new LoggingTunerErrorListener());
List<TunerChannel> tunerChannels = getTunerChannels(tuner);

View File

@@ -20,18 +20,17 @@ package io.github.dsheirer.gui.channelizer;
import io.github.dsheirer.buffer.FloatNativeBuffer;
import io.github.dsheirer.buffer.INativeBuffer;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.complex.ComplexSamples;
import io.github.dsheirer.settings.SettingsManager;
import io.github.dsheirer.source.ISourceEventProcessor;
import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.SourceException;
import io.github.dsheirer.source.tuner.LoggingTunerErrorListener;
import io.github.dsheirer.source.tuner.Tuner;
import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
import io.github.dsheirer.source.tuner.channel.TunerChannel;
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
import io.github.dsheirer.source.tuner.test.TestTuner;
import io.github.dsheirer.spectrum.ComplexDftProcessor;
import io.github.dsheirer.spectrum.DFTSize;
@@ -41,10 +40,18 @@ import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JToggleButton;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
@@ -56,7 +63,7 @@ public class ChannelizerViewer2 extends JFrame
private static final int CHANNEL_BANDWIDTH = 12500;
private SettingsManager mSettingsManager = new SettingsManager(new TunerConfigurationModel());
private SettingsManager mSettingsManager = new SettingsManager();
private JPanel mPrimaryPanel;
private JPanel mControlPanel;
private JButton mTopFrameAddChannelButton;
@@ -68,7 +75,7 @@ public class ChannelizerViewer2 extends JFrame
private ChannelArrayPanel mBottomChannelArrayPanel;
private DFTSize mMainPanelDFTSize = DFTSize.FFT32768;
private DFTSize mChannelPanelDFTSize = DFTSize.FFT04096;
private TestTuner mTestTuner = new TestTuner(new UserPreferences());
private TestTuner mTestTuner = new TestTuner(new LoggingTunerErrorListener());
/**
* GUI Test utility for researching polyphase channelizers.

View File

@@ -20,18 +20,17 @@ package io.github.dsheirer.gui.channelizer;
import io.github.dsheirer.buffer.FloatNativeBuffer;
import io.github.dsheirer.buffer.INativeBuffer;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.complex.ComplexSamples;
import io.github.dsheirer.settings.SettingsManager;
import io.github.dsheirer.source.ISourceEventProcessor;
import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.SourceException;
import io.github.dsheirer.source.tuner.LoggingTunerErrorListener;
import io.github.dsheirer.source.tuner.Tuner;
import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
import io.github.dsheirer.source.tuner.channel.TunerChannel;
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
import io.github.dsheirer.source.tuner.test.TestTuner;
import io.github.dsheirer.spectrum.ComplexDftProcessor;
import io.github.dsheirer.spectrum.DFTSize;
@@ -41,10 +40,16 @@ import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JToggleButton;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
@@ -58,7 +63,7 @@ public class HeterodyneChannelizerViewer extends JFrame
private static final int CHANNEL_BANDWIDTH = 12500;
private static final int CHANNEL_FFT_FRAME_RATE = 20;
private SettingsManager mSettingsManager = new SettingsManager(new TunerConfigurationModel());
private SettingsManager mSettingsManager = new SettingsManager();
private JPanel mPrimaryPanel;
private JPanel mControlPanel;
private JLabel mToneFrequencyLabel;
@@ -77,7 +82,7 @@ public class HeterodyneChannelizerViewer extends JFrame
*/
public HeterodyneChannelizerViewer()
{
mTestTuner = new TestTuner(new UserPreferences());
mTestTuner = new TestTuner(new LoggingTunerErrorListener());
mChannelCount = 5;
mChannelsPerRow = 5;
init();
@@ -516,7 +521,7 @@ public class HeterodyneChannelizerViewer extends JFrame
}
else
{
TestTuner tuner = new TestTuner(new UserPreferences());
TestTuner tuner = new TestTuner(new LoggingTunerErrorListener());
List<TunerChannel> tunerChannels = getTunerChannels(tuner);

View File

@@ -29,7 +29,6 @@ import io.github.dsheirer.dsp.oscillator.OscillatorFactory;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.complex.ComplexSamples;
import io.github.dsheirer.settings.SettingsManager;
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
import io.github.dsheirer.spectrum.ComplexDftProcessor;
import io.github.dsheirer.spectrum.DFTSize;
import io.github.dsheirer.spectrum.SpectrumPanel;
@@ -39,10 +38,15 @@ import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.util.concurrent.TimeUnit;
public class SynthesizerViewer extends JFrame
@@ -54,7 +58,7 @@ public class SynthesizerViewer extends JFrame
private static final int CHANNEL_FFT_FRAME_RATE = 20; //frames per second
private static final int DATA_GENERATOR_FRAME_RATE = 50; //frames per second
private SettingsManager mSettingsManager = new SettingsManager(new TunerConfigurationModel());
private SettingsManager mSettingsManager = new SettingsManager();
private JPanel mPrimaryPanel;
private PrimarySpectrumPanel mPrimarySpectrumPanel;
private ChannelPanel mChannel1Panel;

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2017 Dennis Sheirer
/*
* *****************************************************************************
* Copyright (C) 2014-2022 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
@@ -14,7 +14,8 @@
*
* 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 io.github.dsheirer.source.ISourceEventProcessor;
@@ -69,12 +70,6 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor
init();
}
public JFrequencyControl(long value)
{
this();
mFrequency = value;
}
private void init()
{
setLayout(new MigLayout("insets 0 0 0 0", "[]0[]", ""));
@@ -91,8 +86,7 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor
}
catch(ParseException e)
{
mLog.error("JFrequencyControl - parse exception "
+ "constructing a digit - " + e);
mLog.error("JFrequencyControl - parse exception constructing a digit - " + e);
}
if(digit != null)
@@ -105,15 +99,11 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor
if(x == 6)
{
JLabel period = new JLabel(".");
add(period);
add(new JLabel(". "));
}
}
}
add(new JLabel(" MHz"));
/**
* Create a blank cursor to use when the mouse is over the digits
*/
@@ -123,11 +113,7 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor
//Create image for cursor using empty array
Image cursorImage = Toolkit.getDefaultToolkit().createImage(imageByte);
mBlankCursor = Toolkit.getDefaultToolkit()
.createCustomCursor(cursorImage, new Point(0, 0), "cursor");
setTooltip(false);
mBlankCursor = Toolkit.getDefaultToolkit().createCustomCursor(cursorImage, new Point(0, 0), "cursor");
revalidate();
}
@@ -142,26 +128,6 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor
}
}
private void setTooltip(boolean locked)
{
String tooltip = null;
if(locked)
{
tooltip = "Frequency control is locked. Disable decoding channels to unlock.";
}
else
{
tooltip = "Click on a frequency digit and type a frequency value, or click the upper/lower digits to " +
"change the value";
}
for(Digit digit: mDigits.values())
{
digit.setToolTipText(tooltip);
}
}
/**
* Receives a frequency change event invoked by another control. We don't
* rebroadcast this event, just set the control to indicate the new frequency.
@@ -172,36 +138,7 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor
switch(event.getEvent())
{
case NOTIFICATION_FREQUENCY_CHANGE:
EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
setFrequency(event.getValue().longValue(), false);
}
});
break;
case NOTIFICATION_FREQUENCY_AND_SAMPLE_RATE_LOCKED:
EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
setEnabled(false);
setTooltip(true);
}
});
break;
case NOTIFICATION_FREQUENCY_AND_SAMPLE_RATE_UNLOCKED:
EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
setEnabled(true);
setTooltip(false);
}
});
EventQueue.invokeLater(() -> setFrequency(event.getValue().longValue(), false));
break;
}
}
@@ -251,11 +188,30 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor
}
}
/**
* Adds the source event listener
* @param processor
*/
public void addListener(ISourceEventProcessor processor)
{
mProcessors.add(processor);
if(!mProcessors.contains(processor))
{
mProcessors.add(processor);
}
}
/**
* Remove all source event processors
*/
public void clearListeners()
{
mProcessors.clear();
}
/**
* Removes the source event processor
* @param processor
*/
public void removeListener(ISourceEventProcessor processor)
{
mProcessors.remove(processor);
@@ -272,7 +228,7 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor
super("0");
mPower = position;
setToolTipText(getTooltip(mPower));
Listener listener = new Listener();
this.addKeyListener(listener);
@@ -280,6 +236,49 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor
this.addMouseWheelListener(listener);
}
private static String getTooltip(int power)
{
StringBuilder sb = new StringBuilder();
sb.append("Center frequency ");
switch(power)
{
case 0:
sb.append("1 Hertz");
break;
case 1:
sb.append("10 Hertz");
break;
case 2:
sb.append("100 Hertz");
break;
case 3:
sb.append("1 Kilohertz");
break;
case 4:
sb.append("10 Kilohertz");
break;
case 5:
sb.append("100 Kilohertz");
break;
case 6:
sb.append("1 Megahertz");
break;
case 7:
sb.append("10 Megahertz");
break;
case 8:
sb.append("100 Megahertz");
break;
case 9:
sb.append("1 Gigahertz");
break;
}
sb.append(" units. Type a number, use up/down arrows, or click the upper/lower digit control to adjust");
return sb.toString();
}
/**
* Sets this digit to the value of the column in frequency that corresponds
* to the power (ie column) set for this digit. Optionally, fires a

View File

@@ -1,31 +0,0 @@
package io.github.dsheirer.gui.editor;
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
public class EmptyEditor<T> extends Editor<T>
{
private static final long serialVersionUID = 1L;
public EmptyEditor( String descriptor )
{
setLayout( new MigLayout( "insets 0 0 0 0", "[center]", "[grow]" ) );
add( new JLabel( "Please select " + descriptor ), "wrap" );
}
public EmptyEditor()
{
this( "an item" );
}
@Override
public void save()
{
}
@Override
public void reset()
{
}
}

View File

@@ -1,7 +1,6 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2019 Dennis Sheirer
* *****************************************************************************
* Copyright (C) 2014-2022 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
@@ -15,7 +14,7 @@
*
* 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.instrument.decoder;

View File

@@ -32,6 +32,7 @@ import io.github.dsheirer.gui.preference.PreferenceEditorType;
import io.github.dsheirer.gui.preference.ViewUserPreferenceEditorRequest;
import io.github.dsheirer.playlist.PlaylistManager;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import io.github.dsheirer.util.ThreadPool;
import io.github.dsheirer.util.TimeStamp;
import javafx.application.Platform;
@@ -65,6 +66,7 @@ public class PlaylistEditor extends BorderPane
private static final Logger mLog = LoggerFactory.getLogger(PlaylistEditor.class);
private PlaylistManager mPlaylistManager;
private TunerManager mTunerManager;
private UserPreferences mUserPreferences;
private MenuBar mMenuBar;
private TabPane mTabPane;
@@ -79,11 +81,13 @@ public class PlaylistEditor extends BorderPane
/**
* Constructs an instance
* @param playlistManager for alias and channel models
* @param tunerManager for tuners
* @param userPreferences for settings
*/
public PlaylistEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
public PlaylistEditor(PlaylistManager playlistManager, TunerManager tunerManager, UserPreferences userPreferences)
{
mPlaylistManager = playlistManager;
mTunerManager = tunerManager;
mUserPreferences = userPreferences;
//Throw a new runnable back onto the FX thread to lazy load the editor content after the editor has been
@@ -240,7 +244,7 @@ public class PlaylistEditor extends BorderPane
{
if(mChannelEditor == null)
{
mChannelEditor = new ChannelEditor(mPlaylistManager, mUserPreferences);
mChannelEditor = new ChannelEditor(mPlaylistManager, mTunerManager, mUserPreferences);
}
return mChannelEditor;

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer
* Copyright (C) 2014-2022 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
@@ -20,17 +20,12 @@
package io.github.dsheirer.gui.playlist;
import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.audio.broadcast.BroadcastModel;
import io.github.dsheirer.controller.channel.map.ChannelMapModel;
import io.github.dsheirer.gui.JavaFxWindowManager;
import io.github.dsheirer.icon.IconModel;
import io.github.dsheirer.module.log.EventLogManager;
import io.github.dsheirer.playlist.PlaylistManager;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.settings.SettingsManager;
import io.github.dsheirer.source.SourceManager;
import io.github.dsheirer.source.tuner.TunerModel;
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;
@@ -43,6 +38,7 @@ public class PlaylistEditorApplication extends Application
{
private Stage mStage;
private Parent mPlaylistEditor;
private TunerManager mTunerManager;
private UserPreferences mUserPreferences = new UserPreferences();
private PlaylistManager mPlaylistManager;
private JavaFxWindowManager mJavaFxWindowManager;
@@ -50,17 +46,13 @@ public class PlaylistEditorApplication extends Application
public PlaylistEditorApplication()
{
AliasModel aliasModel = new AliasModel();
BroadcastModel broadcastModel = new BroadcastModel(aliasModel, new IconModel(), mUserPreferences);
ChannelMapModel channelMapModel = new ChannelMapModel();
TunerConfigurationModel tunerConfigurationModel = new TunerConfigurationModel();
TunerModel tunerModel = new TunerModel(tunerConfigurationModel);
SourceManager sourceManager = new SourceManager(tunerModel, new SettingsManager(tunerConfigurationModel),
mUserPreferences);
EventLogManager eventLogManager = new EventLogManager(aliasModel, mUserPreferences);
mPlaylistManager = new PlaylistManager(mUserPreferences, sourceManager, aliasModel, eventLogManager, new IconModel());
mTunerManager = new TunerManager(mUserPreferences);
mTunerManager.start();
mPlaylistManager = new PlaylistManager(mUserPreferences, mTunerManager, aliasModel, eventLogManager, new IconModel());
mPlaylistManager.init();
mJavaFxWindowManager = new JavaFxWindowManager(mUserPreferences, mPlaylistManager);
mJavaFxWindowManager = new JavaFxWindowManager(mUserPreferences, mTunerManager, mPlaylistManager);
}
@Override
@@ -77,7 +69,7 @@ public class PlaylistEditorApplication extends Application
{
if(mPlaylistEditor == null)
{
mPlaylistEditor = new PlaylistEditor(mPlaylistManager, mUserPreferences);
mPlaylistEditor = new PlaylistEditor(mPlaylistManager, mTunerManager, mUserPreferences);
}
return mPlaylistEditor;

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer
* Copyright (C) 2014-2022 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

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer
* Copyright (C) 2014-2022 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

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 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/>
* * *****************************************************************************
* 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.playlist.channel;
@@ -34,6 +31,7 @@ import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.record.RecorderType;
import io.github.dsheirer.record.config.RecordConfiguration;
import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.scene.control.Label;
@@ -59,11 +57,14 @@ public class AMConfigurationEditor extends ChannelConfigurationEditor
/**
* Constructs an instance
* @param playlistManager
* @param playlistManager for playlists
* @param tunerManager for tuners
* @param userPreferences for preferences
*/
public AMConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
public AMConfigurationEditor(PlaylistManager playlistManager, TunerManager tunerManager,
UserPreferences userPreferences)
{
super(playlistManager, userPreferences);
super(playlistManager, tunerManager, userPreferences);
getTitledPanesBox().getChildren().add(getSourcePane());
getTitledPanesBox().getChildren().add(getDecoderPane());
getTitledPanesBox().getChildren().add(getRecordPane());
@@ -138,7 +139,7 @@ public class AMConfigurationEditor extends ChannelConfigurationEditor
{
if(mSourceConfigurationEditor == null)
{
mSourceConfigurationEditor = new FrequencyEditor(getTunerModel());
mSourceConfigurationEditor = new FrequencyEditor(mTunerManager);
//Add a listener so that we can push change notifications up to this editor
mSourceConfigurationEditor.modifiedProperty()

View File

@@ -36,7 +36,7 @@ import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.record.config.RecordConfiguration;
import io.github.dsheirer.source.config.SourceConfigTuner;
import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.TunerModel;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import io.github.dsheirer.util.ThreadPool;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
@@ -80,6 +80,7 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
private final static Logger mLog = LoggerFactory.getLogger(ChannelConfigurationEditor.class);
private PlaylistManager mPlaylistManager;
protected TunerManager mTunerManager;
protected UserPreferences mUserPreferences;
protected EditorModificationListener mEditorModificationListener = new EditorModificationListener();
private Button mPlayButton;
@@ -100,9 +101,17 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
private IconNode mStopGraphicNode;
private ChannelProcessingMonitor mChannelProcessingMonitor = new ChannelProcessingMonitor();
public ChannelConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
/**
* Constructs an instance
* @param playlistManager for playlists
* @param tunerManager for tuners
* @param userPreferences for preferences
*/
public ChannelConfigurationEditor(PlaylistManager playlistManager, TunerManager tunerManager,
UserPreferences userPreferences)
{
mPlaylistManager = playlistManager;
mTunerManager = tunerManager;
mUserPreferences = userPreferences;
setMaxWidth(Double.MAX_VALUE);
@@ -236,11 +245,6 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
modifiedProperty().setValue(false);
}
protected TunerModel getTunerModel()
{
return mPlaylistManager.getTunerModel();
}
@Override
public void save()
{

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 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/>
* * *****************************************************************************
* 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.playlist.channel;
@@ -25,6 +22,7 @@ package io.github.dsheirer.gui.playlist.channel;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.playlist.PlaylistManager;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -46,28 +44,28 @@ public class ChannelConfigurationEditorFactory
* @return constructed editor
*/
public static ChannelConfigurationEditor getEditor(DecoderType decoderType, PlaylistManager playlistManager,
UserPreferences userPreferences)
TunerManager tunerManager, UserPreferences userPreferences)
{
switch(decoderType)
{
case AM:
return new AMConfigurationEditor(playlistManager, userPreferences);
return new AMConfigurationEditor(playlistManager, tunerManager, userPreferences);
case DMR:
return new DMRConfigurationEditor(playlistManager, userPreferences);
return new DMRConfigurationEditor(playlistManager, tunerManager, userPreferences);
case NBFM:
return new NBFMConfigurationEditor(playlistManager, userPreferences);
return new NBFMConfigurationEditor(playlistManager, tunerManager, userPreferences);
case LTR_NET:
return new LTRNetConfigurationEditor(playlistManager, userPreferences);
return new LTRNetConfigurationEditor(playlistManager, tunerManager, userPreferences);
case LTR:
return new LTRConfigurationEditor(playlistManager, userPreferences);
return new LTRConfigurationEditor(playlistManager, tunerManager, userPreferences);
case MPT1327:
return new MPT1327ConfigurationEditor(playlistManager, userPreferences);
return new MPT1327ConfigurationEditor(playlistManager, tunerManager, userPreferences);
case PASSPORT:
return new PassportConfigurationEditor(playlistManager, userPreferences);
return new PassportConfigurationEditor(playlistManager, tunerManager, userPreferences);
case P25_PHASE1:
return new P25P1ConfigurationEditor(playlistManager, userPreferences);
return new P25P1ConfigurationEditor(playlistManager, tunerManager, userPreferences);
case P25_PHASE2:
return new P25P2ConfigurationEditor(playlistManager, userPreferences);
return new P25P2ConfigurationEditor(playlistManager, tunerManager, userPreferences);
default:
if(decoderType != null && !mLoggedUnrecognizedTypes.contains(decoderType))
{

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 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/>
* * *****************************************************************************
* 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.playlist.channel;
@@ -28,6 +25,7 @@ import io.github.dsheirer.module.decode.DecoderFactory;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.playlist.PlaylistManager;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
@@ -79,6 +77,7 @@ public class ChannelEditor extends SplitPane
{
private final static Logger mLog = LoggerFactory.getLogger(ChannelEditor.class);
private PlaylistManager mPlaylistManager;
private TunerManager mTunerManager;
private UserPreferences mUserPreferences;
private TableView<Channel> mChannelTableView;
private Label mPlaceholderLabel;
@@ -102,11 +101,12 @@ public class ChannelEditor extends SplitPane
* Constructs an instance
* @param playlistManager containing playlists and channel configurations
*/
public ChannelEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
public ChannelEditor(PlaylistManager playlistManager, TunerManager tunerManager, UserPreferences userPreferences)
{
mPlaylistManager = playlistManager;
mTunerManager = tunerManager;
mUserPreferences = userPreferences;
mUnknownConfigurationEditor = new UnknownConfigurationEditor(mPlaylistManager, userPreferences);
mUnknownConfigurationEditor = new UnknownConfigurationEditor(mPlaylistManager, mTunerManager, userPreferences);
HBox channelsBox = new HBox();
channelsBox.setSpacing(10.0);
@@ -203,7 +203,7 @@ public class ChannelEditor extends SplitPane
if(editor == null)
{
editor = ChannelConfigurationEditorFactory.getEditor(channelDecoderType, mPlaylistManager,
mUserPreferences);
mTunerManager, mUserPreferences);
if(editor != null)
{

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 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/>
* * *****************************************************************************
* 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.playlist.channel;
@@ -40,6 +37,7 @@ import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.record.RecorderType;
import io.github.dsheirer.record.config.RecordConfiguration;
import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
@@ -96,11 +94,14 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
/**
* Constructs an instance
* @param playlistManager
* @param playlistManager for playlists
* @param tunerManager for tuners
* @param userPreferences for preferences
*/
public DMRConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
public DMRConfigurationEditor(PlaylistManager playlistManager, TunerManager tunerManager,
UserPreferences userPreferences)
{
super(playlistManager, userPreferences);
super(playlistManager, tunerManager, userPreferences);
getTitledPanesBox().getChildren().add(getSourcePane());
getTitledPanesBox().getChildren().add(getDecoderPane());
getTitledPanesBox().getChildren().add(getEventLogPane());
@@ -240,7 +241,7 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
{
if(mSourceConfigurationEditor == null)
{
mSourceConfigurationEditor = new FrequencyEditor(getTunerModel(),
mSourceConfigurationEditor = new FrequencyEditor(mTunerManager,
DecodeConfigDMR.CHANNEL_ROTATION_DELAY_MINIMUM_MS,
DecodeConfigDMR.CHANNEL_ROTATION_DELAY_MAXIMUM_MS,
DecodeConfigDMR.CHANNEL_ROTATION_DELAY_DEFAULT_MS);

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 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/>
* * *****************************************************************************
* 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.playlist.channel;
@@ -39,6 +36,7 @@ import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.record.RecorderType;
import io.github.dsheirer.record.config.RecordConfiguration;
import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.scene.control.Label;
@@ -74,12 +72,14 @@ public class LTRConfigurationEditor extends ChannelConfigurationEditor
/**
* Constructs an instance
* @param playlistManager
* @param userPreferences
* @param playlistManager for playlists
* @param tunerManager for tuners
* @param userPreferences for preferences
*/
public LTRConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
public LTRConfigurationEditor(PlaylistManager playlistManager, TunerManager tunerManager,
UserPreferences userPreferences)
{
super(playlistManager, userPreferences);
super(playlistManager, tunerManager, userPreferences);
getTitledPanesBox().getChildren().add(getSourcePane());
getTitledPanesBox().getChildren().add(getDecoderPane());
getTitledPanesBox().getChildren().add(getAuxDecoderPane());
@@ -210,7 +210,7 @@ public class LTRConfigurationEditor extends ChannelConfigurationEditor
{
if(mSourceConfigurationEditor == null)
{
mSourceConfigurationEditor = new FrequencyEditor(getTunerModel());
mSourceConfigurationEditor = new FrequencyEditor(mTunerManager);
//Add a listener so that we can push change notifications up to this editor
mSourceConfigurationEditor.modifiedProperty()

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 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/>
* * *****************************************************************************
* 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.playlist.channel;
@@ -39,6 +36,7 @@ import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.record.RecorderType;
import io.github.dsheirer.record.config.RecordConfiguration;
import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.scene.control.Label;
@@ -74,12 +72,13 @@ public class LTRNetConfigurationEditor extends ChannelConfigurationEditor
/**
* Constructs an instance
* @param playlistManager
* @param userPreferences
* @param playlistManager for playlists
* @param tunerManager for tuners
* @param userPreferences for preferences
*/
public LTRNetConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
public LTRNetConfigurationEditor(PlaylistManager playlistManager, TunerManager tunerManager, UserPreferences userPreferences)
{
super(playlistManager, userPreferences);
super(playlistManager, tunerManager, userPreferences);
getTitledPanesBox().getChildren().add(getSourcePane());
getTitledPanesBox().getChildren().add(getDecoderPane());
getTitledPanesBox().getChildren().add(getAuxDecoderPane());
@@ -210,7 +209,7 @@ public class LTRNetConfigurationEditor extends ChannelConfigurationEditor
{
if(mSourceConfigurationEditor == null)
{
mSourceConfigurationEditor = new FrequencyEditor(getTunerModel());
mSourceConfigurationEditor = new FrequencyEditor(mTunerManager);
//Add a listener so that we can push change notifications up to this editor
mSourceConfigurationEditor.modifiedProperty()

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 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/>
* * *****************************************************************************
* 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.playlist.channel;
@@ -40,6 +37,7 @@ import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.record.RecorderType;
import io.github.dsheirer.record.config.RecordConfiguration;
import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
@@ -84,12 +82,14 @@ public class MPT1327ConfigurationEditor extends ChannelConfigurationEditor
/**
* Constructs an instance
* @param playlistManager
* @param userPreferences
* @param playlistManager for playlists
* @param tunerManager for tuners
* @param userPreferences for preferences
*/
public MPT1327ConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
public MPT1327ConfigurationEditor(PlaylistManager playlistManager, TunerManager tunerManager,
UserPreferences userPreferences)
{
super(playlistManager, userPreferences);
super(playlistManager, tunerManager, userPreferences);
getTitledPanesBox().getChildren().add(getSourcePane());
getTitledPanesBox().getChildren().add(getDecoderPane());
getTitledPanesBox().getChildren().add(getEventLogPane());
@@ -195,7 +195,7 @@ public class MPT1327ConfigurationEditor extends ChannelConfigurationEditor
{
if(mSourceConfigurationEditor == null)
{
mSourceConfigurationEditor = new FrequencyEditor(getTunerModel(),
mSourceConfigurationEditor = new FrequencyEditor(mTunerManager,
DecodeConfigMPT1327.CHANNEL_ROTATION_DELAY_MINIMUM_MS,
DecodeConfigMPT1327.CHANNEL_ROTATION_DELAY_MAXIMUM_MS,
DecodeConfigMPT1327.CHANNEL_ROTATION_DELAY_DEFAULT_MS);

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 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/>
* * *****************************************************************************
* 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.playlist.channel;
@@ -42,6 +39,7 @@ import io.github.dsheirer.protocol.Protocol;
import io.github.dsheirer.record.RecorderType;
import io.github.dsheirer.record.config.RecordConfiguration;
import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener;
@@ -92,12 +90,14 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor
/**
* Constructs an instance
* @param playlistManager
* @param userPreferences
* @param playlistManager for playlists
* @param tunerManager for tuners
* @param userPreferences for preferences
*/
public NBFMConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
public NBFMConfigurationEditor(PlaylistManager playlistManager, TunerManager tunerManager,
UserPreferences userPreferences)
{
super(playlistManager, userPreferences);
super(playlistManager, tunerManager, userPreferences);
getTitledPanesBox().getChildren().add(getSourcePane());
getTitledPanesBox().getChildren().add(getDecoderPane());
getTitledPanesBox().getChildren().add(getAuxDecoderPane());
@@ -228,7 +228,7 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor
{
if(mSourceConfigurationEditor == null)
{
mSourceConfigurationEditor = new FrequencyEditor(getTunerModel());
mSourceConfigurationEditor = new FrequencyEditor(mTunerManager);
//Add a listener so that we can push change notifications up to this editor
mSourceConfigurationEditor.modifiedProperty()

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 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/>
* * *****************************************************************************
* 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.playlist.channel;
@@ -38,6 +35,7 @@ import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.record.RecorderType;
import io.github.dsheirer.record.config.RecordConfiguration;
import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.HPos;
@@ -80,12 +78,14 @@ public class P25P1ConfigurationEditor extends ChannelConfigurationEditor
/**
* Constructs an instance
* @param playlistManager
* @param userPreferences
* @param playlistManager for playlists
* @param tunerManager for tuners
* @param userPreferences for preferences
*/
public P25P1ConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
public P25P1ConfigurationEditor(PlaylistManager playlistManager, TunerManager tunerManager,
UserPreferences userPreferences)
{
super(playlistManager, userPreferences);
super(playlistManager, tunerManager, userPreferences);
getTitledPanesBox().getChildren().add(getSourcePane());
getTitledPanesBox().getChildren().add(getDecoderPane());
getTitledPanesBox().getChildren().add(getEventLogPane());
@@ -191,7 +191,7 @@ public class P25P1ConfigurationEditor extends ChannelConfigurationEditor
{
if(mSourceConfigurationEditor == null)
{
mSourceConfigurationEditor = new FrequencyEditor(getTunerModel(),
mSourceConfigurationEditor = new FrequencyEditor(mTunerManager,
DecodeConfigP25Phase1.CHANNEL_ROTATION_DELAY_MINIMUM_MS,
DecodeConfigP25Phase1.CHANNEL_ROTATION_DELAY_MAXIMUM_MS,
DecodeConfigP25Phase1.CHANNEL_ROTATION_DELAY_DEFAULT_MS);

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 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/>
* * *****************************************************************************
* 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.playlist.channel;
@@ -39,6 +36,7 @@ import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.record.RecorderType;
import io.github.dsheirer.record.config.RecordConfiguration;
import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.scene.control.Label;
@@ -73,9 +71,10 @@ public class P25P2ConfigurationEditor extends ChannelConfigurationEditor
* @param playlistManager
* @param userPreferences
*/
public P25P2ConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
public P25P2ConfigurationEditor(PlaylistManager playlistManager, TunerManager tunerManager,
UserPreferences userPreferences)
{
super(playlistManager, userPreferences);
super(playlistManager, tunerManager, userPreferences);
getTitledPanesBox().getChildren().add(getSourcePane());
getTitledPanesBox().getChildren().add(getDecoderPane());
getTitledPanesBox().getChildren().add(getEventLogPane());
@@ -179,7 +178,7 @@ public class P25P2ConfigurationEditor extends ChannelConfigurationEditor
{
if(mSourceConfigurationEditor == null)
{
mSourceConfigurationEditor = new FrequencyEditor(getTunerModel());
mSourceConfigurationEditor = new FrequencyEditor(mTunerManager);
//Add a listener so that we can push change notifications up to this editor
mSourceConfigurationEditor.modifiedProperty()

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 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/>
* * *****************************************************************************
* 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.playlist.channel;
@@ -38,6 +35,7 @@ import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.record.RecorderType;
import io.github.dsheirer.record.config.RecordConfiguration;
import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.geometry.Insets;
import javafx.scene.control.Label;
import javafx.scene.control.TitledPane;
@@ -69,9 +67,10 @@ public class PassportConfigurationEditor extends ChannelConfigurationEditor
* @param playlistManager
* @param userPreferences
*/
public PassportConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
public PassportConfigurationEditor(PlaylistManager playlistManager, TunerManager tunerManager,
UserPreferences userPreferences)
{
super(playlistManager, userPreferences);
super(playlistManager, tunerManager, userPreferences);
getTitledPanesBox().getChildren().add(getSourcePane());
getTitledPanesBox().getChildren().add(getDecoderPane());
getTitledPanesBox().getChildren().add(getAuxDecoderPane());
@@ -155,7 +154,7 @@ public class PassportConfigurationEditor extends ChannelConfigurationEditor
{
if(mSourceConfigurationEditor == null)
{
mSourceConfigurationEditor = new FrequencyEditor(getTunerModel());
mSourceConfigurationEditor = new FrequencyEditor(mTunerManager);
//Add a listener so that we can push change notifications up to this editor
mSourceConfigurationEditor.modifiedProperty()

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 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/>
* * *****************************************************************************
* 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.playlist.channel;
@@ -30,6 +27,7 @@ import io.github.dsheirer.playlist.PlaylistManager;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.record.config.RecordConfiguration;
import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.scene.control.TitledPane;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -46,9 +44,10 @@ public class UnknownConfigurationEditor extends ChannelConfigurationEditor
* Constructs an instance
* @param aliasModel
*/
public UnknownConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
public UnknownConfigurationEditor(PlaylistManager playlistManager, TunerManager tunerManager,
UserPreferences userPreferences)
{
super(playlistManager, userPreferences);
super(playlistManager, tunerManager, userPreferences);
getTitledPanesBox().getChildren().add(getDecoderPane());
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer
* Copyright (C) 2014-2022 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

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer
* Copyright (C) 2014-2022 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

View File

@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 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/>
* * *****************************************************************************
* 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.playlist.source;
@@ -25,8 +22,8 @@ package io.github.dsheirer.gui.playlist.source;
import io.github.dsheirer.source.config.SourceConfigTuner;
import io.github.dsheirer.source.config.SourceConfigTunerMultipleFrequency;
import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.TunerModel;
import io.github.dsheirer.source.tuner.channel.rotation.ChannelRotationMonitor;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.beans.binding.Bindings;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
@@ -59,7 +56,7 @@ public class FrequencyEditor extends SourceConfigurationEditor<SourceConfigurati
{
private final static Logger mLog = LoggerFactory.getLogger(FrequencyEditor.class);
private static final String NONE = "(none) ";
private TunerModel mTunerModel;
private TunerManager mTunerManager;
private FrequencyBox mPrimaryFrequencyBox;
private ObservableList<FrequencyBox> mFrequencyBoxes = FXCollections.observableArrayList();
private ComboBox<String> mPreferredTunerComboBox;
@@ -75,13 +72,13 @@ public class FrequencyEditor extends SourceConfigurationEditor<SourceConfigurati
* define constraints for the channel rotation delay monitor, how long the monitor dwells on each frequency in a
* multi-frequency configuration.
*
* @param tunerModel for accessing list of tuners to select a preferred tuner
* @param tunerManager for accessing list of tuners to select a preferred tuner
* @param minRotationDelay in milliseconds for channel/frequency dwell
* @param maxRotationDelay in milliseconds for channel/frequency dwell
*/
public FrequencyEditor(TunerModel tunerModel, int minRotationDelay, int maxRotationDelay, int defaultRotationDelay)
public FrequencyEditor(TunerManager tunerManager, int minRotationDelay, int maxRotationDelay, int defaultRotationDelay)
{
mTunerModel = tunerModel;
mTunerManager = tunerManager;
mAllowMultipleFrequencies = true;
mFrequencyRotationMinimum = minRotationDelay;
mFrequencyRotationMaximum = maxRotationDelay;
@@ -91,11 +88,11 @@ public class FrequencyEditor extends SourceConfigurationEditor<SourceConfigurati
/**
* Constructs an instance with a default behavior of single frequency support only.
* @param tunerModel for accessing list of tuners to select a preferred tuner
* @param tunerManager for accessing list of tuners to select a preferred tuner
*/
public FrequencyEditor(TunerModel tunerModel)
public FrequencyEditor(TunerManager tunerManager)
{
mTunerModel = tunerModel;
mTunerManager = tunerManager;
init();
}
@@ -333,9 +330,9 @@ public class FrequencyEditor extends SourceConfigurationEditor<SourceConfigurati
getPreferredTunerComboBox().getItems().clear();
getPreferredTunerComboBox().getItems().add(NONE);
if(mTunerModel != null)
if(mTunerManager != null)
{
getPreferredTunerComboBox().getItems().addAll(mTunerModel.getTunerNames());
getPreferredTunerComboBox().getItems().addAll(mTunerManager.getPreferredTunerNames());
}
}

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