diff --git a/src/main/java/io/github/dsheirer/audio/AudioModule.java b/src/main/java/io/github/dsheirer/audio/AudioModule.java index a12e66597..29c17215c 100644 --- a/src/main/java/io/github/dsheirer/audio/AudioModule.java +++ b/src/main/java/io/github/dsheirer/audio/AudioModule.java @@ -43,6 +43,7 @@ public class AudioModule extends AbstractAudioModule implements ISquelchStateLis { private static final Logger mLog = LoggerFactory.getLogger(AudioModule.class); private static float[] sHighPassFilterCoefficients; + private final boolean mAudioFilterEnable; static { @@ -70,27 +71,33 @@ public class AudioModule extends AbstractAudioModule implements ISquelchStateLis } } - private IRealFilter mHighPassFilter = FilterFactory.getRealFilter(sHighPassFilterCoefficients); - private SquelchStateListener mSquelchStateListener = new SquelchStateListener(); + private final IRealFilter mHighPassFilter = FilterFactory.getRealFilter(sHighPassFilterCoefficients); + private final SquelchStateListener mSquelchStateListener = new SquelchStateListener(); private SquelchState mSquelchState = SquelchState.SQUELCH; /** * Creates an Audio Module. * * @param aliasList for aliasing identifiers + * @param timeslot for this audio module * @param maxAudioSegmentLength in milliseconds + * @param audioFilterEnable to enable or disable high-pass audio filter */ - public AudioModule(AliasList aliasList, int timeslot, long maxAudioSegmentLength) + public AudioModule(AliasList aliasList, int timeslot, long maxAudioSegmentLength, boolean audioFilterEnable) { super(aliasList, timeslot, maxAudioSegmentLength); + mAudioFilterEnable = audioFilterEnable; } /** * Creates an Audio Module. + * @param aliasList for aliasing identifiers + * @param audioFilterEnable to enable or disable high-pass audio filter */ - public AudioModule(AliasList aliasList) + public AudioModule(AliasList aliasList, boolean audioFilterEnable) { super(aliasList); + mAudioFilterEnable = audioFilterEnable; } @Override @@ -121,7 +128,11 @@ public void receive(float[] audioBuffer) { if(mSquelchState == SquelchState.UNSQUELCH) { - audioBuffer = mHighPassFilter.filter(audioBuffer); + if(mAudioFilterEnable) + { + audioBuffer = mHighPassFilter.filter(audioBuffer); + } + addAudio(audioBuffer); } } diff --git a/src/main/java/io/github/dsheirer/gui/playlist/channel/NBFMConfigurationEditor.java b/src/main/java/io/github/dsheirer/gui/playlist/channel/NBFMConfigurationEditor.java index 4b70ad215..aca8c2e7e 100644 --- a/src/main/java/io/github/dsheirer/gui/playlist/channel/NBFMConfigurationEditor.java +++ b/src/main/java/io/github/dsheirer/gui/playlist/channel/NBFMConfigurationEditor.java @@ -27,6 +27,7 @@ import io.github.dsheirer.gui.playlist.source.FrequencyEditor; import io.github.dsheirer.gui.playlist.source.SourceConfigurationEditor; import io.github.dsheirer.module.decode.DecoderType; +import io.github.dsheirer.module.decode.analog.DecodeConfigAnalog; import io.github.dsheirer.module.decode.config.AuxDecodeConfiguration; import io.github.dsheirer.module.decode.config.DecodeConfiguration; import io.github.dsheirer.module.decode.nbfm.DecodeConfigNBFM; @@ -40,8 +41,6 @@ import io.github.dsheirer.record.config.RecordConfiguration; import io.github.dsheirer.source.config.SourceConfiguration; import io.github.dsheirer.source.tuner.manager.TunerManager; -import java.util.ArrayList; -import java.util.List; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.collections.ListChangeListener; @@ -58,15 +57,15 @@ import javafx.scene.text.TextAlignment; import org.controlsfx.control.SegmentedButton; import org.controlsfx.control.ToggleSwitch; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; /** * Narrow-Band FM channel configuration editor */ public class NBFMConfigurationEditor extends ChannelConfigurationEditor { - private final static Logger mLog = LoggerFactory.getLogger(NBFMConfigurationEditor.class); private TitledPane mAuxDecoderPane; private TitledPane mDecoderPane; private TitledPane mEventLogPane; @@ -75,8 +74,9 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor private TextField mTalkgroupField; private TextField mSquelchThresholdField; private ToggleSwitch mSquelchAutoTrackSwitch; + private ToggleSwitch mAudioFilterEnable; private TextFormatter mTalkgroupTextFormatter; - private IntegerFormatter mSquelchTextFormatter = new IntegerFormatter((int)DbPowerMeter.DEFAULT_MINIMUM_POWER, + private final IntegerFormatter mSquelchTextFormatter = new IntegerFormatter((int)DbPowerMeter.DEFAULT_MINIMUM_POWER, (int)DbPowerMeter.DEFAULT_MAXIMUM_POWER); private ToggleSwitch mBasebandRecordSwitch; private SegmentedButton mBandwidthButton; @@ -84,9 +84,9 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor private SourceConfigurationEditor mSourceConfigurationEditor; private AuxDecoderConfigurationEditor mAuxDecoderConfigurationEditor; private EventLogConfigurationEditor mEventLogConfigurationEditor; - private TalkgroupValueChangeListener mTalkgroupValueChangeListener = new TalkgroupValueChangeListener(); - private IntegerFormatter mDecimalFormatter = new IntegerFormatter(1, 65535); - private HexFormatter mHexFormatter = new HexFormatter(1, 65535); + private final TalkgroupValueChangeListener mTalkgroupValueChangeListener = new TalkgroupValueChangeListener(); + private final IntegerFormatter mDecimalFormatter = new IntegerFormatter(1, 65535); + private final HexFormatter mHexFormatter = new HexFormatter(1, 65535); /** * Constructs an instance @@ -162,12 +162,15 @@ private TitledPane getDecoderPane() Label talkgroupLabel = new Label("Talkgroup To Assign"); GridPane.setHalignment(talkgroupLabel, HPos.RIGHT); - GridPane.setConstraints(talkgroupLabel, 6, 0); + GridPane.setConstraints(talkgroupLabel, 0, 1); gridPane.getChildren().add(talkgroupLabel); - GridPane.setConstraints(getTalkgroupField(), 7, 0); + GridPane.setConstraints(getTalkgroupField(), 1, 1); gridPane.getChildren().add(getTalkgroupField()); + GridPane.setConstraints(getAudioFilterEnable(), 2, 1); + gridPane.getChildren().add(getAudioFilterEnable()); + mDecoderPane.setContent(gridPane); //Special handling - the pill button doesn't like to set a selected state if the pane is not expanded, @@ -275,6 +278,22 @@ private AuxDecoderConfigurationEditor getAuxDecoderConfigurationEditor() return mAuxDecoderConfigurationEditor; } + /** + * Toggle switch for enable/disable the audio filtering in the audio module. + * @return toggle switch. + */ + private ToggleSwitch getAudioFilterEnable() + { + if(mAudioFilterEnable == null) + { + mAudioFilterEnable = new ToggleSwitch("High-Pass Audio Filter"); + mAudioFilterEnable.setTooltip(new Tooltip("High-pass filter to remove DC offset and sub-audible signalling")); + mAudioFilterEnable.selectedProperty().addListener((observable, oldValue, newValue) -> modifiedProperty().set(true)); + } + + return mAudioFilterEnable; + } + private SegmentedButton getBandwidthButton() { if(mBandwidthButton == null) @@ -298,31 +317,27 @@ private SegmentedButton getBandwidthButton() //decode configuration and we're unable to correctly set the bandwidth setting. As a work //around, we'll listen for the toggles to be added and update them here. This normally only //happens when we first instantiate the editor and load an item for editing the first time. - mBandwidthButton.getToggleGroup().getToggles().addListener(new ListChangeListener() + mBandwidthButton.getToggleGroup().getToggles().addListener((ListChangeListener)c -> { - @Override - public void onChanged(Change c) + //This change event happens when the toggles are added -- we don't need to inspect the change event + if(getItem() != null && getItem().getDecodeConfiguration() instanceof DecodeConfigNBFM) { - //This change event happens when the toggles are added -- we don't need to inspect the change event - if(getItem() != null && getItem().getDecodeConfiguration() instanceof DecodeConfigNBFM) + //Capture current modified state so that we can reapply after adjusting control states + boolean modified = modifiedProperty().get(); + + DecodeConfigNBFM config = (DecodeConfigNBFM)getItem().getDecodeConfiguration(); + DecodeConfigNBFM.Bandwidth bandwidth = config.getBandwidth(); + if(bandwidth == null) { - //Capture current modified state so that we can reapply after adjusting control states - boolean modified = modifiedProperty().get(); - - DecodeConfigNBFM config = (DecodeConfigNBFM)getItem().getDecodeConfiguration(); - DecodeConfigNBFM.Bandwidth bandwidth = config.getBandwidth(); - if(bandwidth == null) - { - bandwidth = DecodeConfigNBFM.Bandwidth.BW_12_5; - } - - for(Toggle toggle: getBandwidthButton().getToggleGroup().getToggles()) - { - toggle.setSelected(toggle.getUserData() == bandwidth); - } - - modifiedProperty().set(modified); + bandwidth = DecodeConfigNBFM.Bandwidth.BW_12_5; } + + for(Toggle toggle: getBandwidthButton().getToggleGroup().getToggles()) + { + toggle.setSelected(toggle.getUserData() == bandwidth); + } + + modifiedProperty().set(modified); } }); } @@ -449,6 +464,8 @@ protected void setDecoderConfiguration(DecodeConfiguration config) mSquelchTextFormatter.setValue(decodeConfigNBFM.getSquelchThreshold()); getSquelchAutoTrackSwitch().setDisable(false); getSquelchAutoTrackSwitch().setSelected(decodeConfigNBFM.isSquelchAutoTrack()); + getAudioFilterEnable().setDisable(false); + getAudioFilterEnable().setSelected(decodeConfigNBFM.isAudioFilter()); } else { @@ -464,6 +481,8 @@ protected void setDecoderConfiguration(DecodeConfiguration config) getSquelchThresholdField().setDisable(true); getSquelchAutoTrackSwitch().setDisable(true); getSquelchAutoTrackSwitch().setSelected(false); + getAudioFilterEnable().setDisable(true); + getAudioFilterEnable().setSelected(false); } } @@ -500,6 +519,7 @@ protected void saveDecoderConfiguration() config.setTalkgroup(talkgroup); config.setSquelchThreshold(mSquelchTextFormatter.getValue()); config.setSquelchAutoTrack(getSquelchAutoTrackSwitch().isSelected()); + config.setAudioFilter(getAudioFilterEnable().isSelected()); getItem().setDecodeConfiguration(config); } diff --git a/src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java b/src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java index 2cd445ddf..9189b7c8a 100644 --- a/src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java +++ b/src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java @@ -105,6 +105,7 @@ public class DecoderFactory { private final static Logger mLog = LoggerFactory.getLogger(DecoderFactory.class); private static final double FM_CHANNEL_BANDWIDTH = 12500.0; + private static final boolean AUDIO_FILTER_ENABLE = true; /** * Returns a list of one primary decoder and any auxiliary decoders, as @@ -246,14 +247,14 @@ private static void processP25Phase1(Channel channel, UserPreferences userPrefer /** * Creates decoder modules for Passport decoder * @param channel configuration - * @param userPreferences reference * @param modules collection to add to * @param aliasList for the channel + * @param decodeConfig for the channel */ private static void processPassport(Channel channel, List modules, AliasList aliasList, DecodeConfiguration decodeConfig) { modules.add(new PassportDecoder(decodeConfig)); modules.add(new PassportDecoderState()); - modules.add(new AudioModule(aliasList)); + modules.add(new AudioModule(aliasList, AUDIO_FILTER_ENABLE)); if(channel.getSourceConfiguration().getSourceType() == SourceType.TUNER) { modules.add(new FMDemodulatorModule(FM_CHANNEL_BANDWIDTH)); @@ -262,10 +263,12 @@ private static void processPassport(Channel channel, List modules, Alias /** * Creates decoder modules for MPT-1327 decoder + * @param channelMapModel to use in calculating traffic channel frequencies * @param channel configuration - * @param userPreferences reference * @param modules collection to add to * @param aliasList for the channel + * @param channelType for control or traffic + * @param decodeConfig configuration */ private static void processMPT1327(ChannelMapModel channelMapModel, Channel channel, List modules, AliasList aliasList, ChannelType channelType, DecodeConfigMPT1327 decodeConfig) { DecodeConfigMPT1327 mptConfig = decodeConfig; @@ -279,7 +282,7 @@ private static void processMPT1327(ChannelMapModel channelMapModel, Channel chan // not create a new segment if the processing chain finishes a bit after // actual call timeout. long maxAudioSegmentLengthMillis = (callTimeoutMilliseconds + 5000); - modules.add(new AudioModule(aliasList, AbstractAudioModule.DEFAULT_TIMESLOT, maxAudioSegmentLengthMillis)); + modules.add(new AudioModule(aliasList, AbstractAudioModule.DEFAULT_TIMESLOT, maxAudioSegmentLengthMillis, AUDIO_FILTER_ENABLE)); SourceType sourceType = channel.getSourceConfiguration().getSourceType(); if(sourceType == SourceType.TUNER || sourceType == SourceType.TUNER_MULTIPLE_FREQUENCIES) @@ -312,14 +315,14 @@ private static void processMPT1327(ChannelMapModel channelMapModel, Channel chan /** * Creates decoder modules for LTR-Net decoder * @param channel configuration - * @param userPreferences reference * @param modules collection to add to * @param aliasList for the channel + * @param decodeConfig for the channel */ private static void processLTRNet(Channel channel, List modules, AliasList aliasList, DecodeConfigLTRNet decodeConfig) { modules.add(new LTRNetDecoder(decodeConfig)); modules.add(new LTRNetDecoderState()); - modules.add(new AudioModule(aliasList)); + modules.add(new AudioModule(aliasList, AUDIO_FILTER_ENABLE)); if(channel.getSourceConfiguration().getSourceType() == SourceType.TUNER) { modules.add(new FMDemodulatorModule(FM_CHANNEL_BANDWIDTH)); @@ -329,15 +332,15 @@ private static void processLTRNet(Channel channel, List modules, AliasLi /** * Creates decoder modules for LTR decoder * @param channel configuration - * @param userPreferences reference * @param modules collection to add to * @param aliasList for the channel + * @param decodeConfig for the channel */ private static void processLTRStandard(Channel channel, List modules, AliasList aliasList, DecodeConfigLTRStandard decodeConfig) { MessageDirection direction = decodeConfig.getMessageDirection(); modules.add(new LTRStandardDecoder(direction)); modules.add(new LTRStandardDecoderState()); - modules.add(new AudioModule(aliasList)); + modules.add(new AudioModule(aliasList, AUDIO_FILTER_ENABLE)); if(channel.getSourceConfiguration().getSourceType() == SourceType.TUNER) { modules.add(new FMDemodulatorModule(FM_CHANNEL_BANDWIDTH)); @@ -347,9 +350,9 @@ private static void processLTRStandard(Channel channel, List modules, Al /** * Creates decoder modules for Narrow Band FM decoder * @param channel configuration - * @param userPreferences reference * @param modules collection to add to * @param aliasList for the channel + * @param decodeConfig for the channel */ private static void processNBFM(Channel channel, List modules, AliasList aliasList, DecodeConfiguration decodeConfig) { @@ -362,15 +365,15 @@ private static void processNBFM(Channel channel, List modules, AliasList DecodeConfigNBFM decodeConfigNBFM = (DecodeConfigNBFM)decodeConfig; modules.add(new NBFMDecoder(decodeConfigNBFM)); modules.add(new NBFMDecoderState(channel.getName(), decodeConfigNBFM)); - modules.add(new AudioModule(aliasList, 0, 60000)); + modules.add(new AudioModule(aliasList, 0, 60000, decodeConfigNBFM.isAudioFilter())); } /** * Creates decoder modules for AM decoder * @param channel configuration - * @param userPreferences reference * @param modules collection to add to * @param aliasList for the channel + * @param decodeConfig for the channel */ private static void processAM(Channel channel, List modules, AliasList aliasList, DecodeConfiguration decodeConfig) { @@ -383,7 +386,7 @@ private static void processAM(Channel channel, List modules, AliasList a DecodeConfigAM decodeConfigAM = (DecodeConfigAM) decodeConfig; modules.add(new AMDecoder(decodeConfigAM)); modules.add(new AMDecoderState(channel.getName(), decodeConfigAM)); - modules.add(new AudioModule(aliasList, 0, 60000)); + modules.add(new AudioModule(aliasList, 0, 60000, AUDIO_FILTER_ENABLE)); } /** @@ -575,7 +578,7 @@ public static DecodeConfiguration getDecodeConfiguration(DecoderType decoder) case P25_PHASE2: return new DecodeConfigP25Phase2(); default: - throw new IllegalArgumentException("DecodeConfigFactory - unknown decoder type [" + decoder.toString() + "]"); + throw new IllegalArgumentException("DecodeConfigFactory - unknown decoder type [" + decoder + "]"); } } diff --git a/src/main/java/io/github/dsheirer/module/decode/nbfm/DecodeConfigNBFM.java b/src/main/java/io/github/dsheirer/module/decode/nbfm/DecodeConfigNBFM.java index 3d1ac92e2..4e0a4cb69 100644 --- a/src/main/java/io/github/dsheirer/module/decode/nbfm/DecodeConfigNBFM.java +++ b/src/main/java/io/github/dsheirer/module/decode/nbfm/DecodeConfigNBFM.java @@ -29,6 +29,11 @@ */ public class DecodeConfigNBFM extends DecodeConfigAnalog { + private boolean mAudioFilter = true; + + /** + * Constructs an instance + */ public DecodeConfigNBFM() { } @@ -62,4 +67,23 @@ public ChannelSpecification getChannelSpecification() throw new IllegalArgumentException("Unrecognized FM bandwidth value: " + getBandwidth()); } } + + /** + * Indicates if the user wants the demodulated audio to be high-pass filtered. + * @return enable status, defaults to true. + */ + @JacksonXmlProperty(isAttribute = true, localName = "audioFilter") + public boolean isAudioFilter() + { + return mAudioFilter; + } + + /** + * Sets the enabled state of high-pass filtering of the demodulated audio. + * @param audioFilter to true to enable high-pass filtering. + */ + public void setAudioFilter(boolean audioFilter) + { + mAudioFilter = audioFilter; + } }