Skip to content

Commit

Permalink
#1847 Updates spectral display to show channel overlay for all freque…
Browse files Browse the repository at this point in the history
…ncies in a channel configuration that contains multiple frequencies. (#1848)

Co-authored-by: Dennis Sheirer <dsheirer@github.com>
  • Loading branch information
DSheirer and Dennis Sheirer committed Feb 11, 2024
1 parent 6532e33 commit 2c32096
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 88 deletions.
107 changes: 62 additions & 45 deletions src/main/java/io/github/dsheirer/controller/channel/Channel.java
@@ -1,23 +1,20 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2024 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;

Expand All @@ -35,13 +32,16 @@
import io.github.dsheirer.record.config.RecordConfiguration;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.SourceType;
import io.github.dsheirer.source.config.SourceConfigFactory;
import io.github.dsheirer.source.config.SourceConfigRecording;
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.channel.TunerChannel;
import java.beans.Transient;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javafx.beans.Observable;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
Expand All @@ -55,9 +55,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.Transient;
import java.util.Objects;

@JacksonXmlRootElement(localName = "channel")
public class Channel extends Configuration implements Listener<SourceEvent>
{
Expand Down Expand Up @@ -88,7 +85,7 @@ public enum ChannelType
private BooleanProperty mAutoStart = new SimpleBooleanProperty();
private IntegerProperty mAutoStartOrder = new SimpleIntegerProperty();
private boolean mSelected;
private TunerChannel mTunerChannel = null;
private List<TunerChannel> mTunerChannels = null;

private ChannelType mChannelType = ChannelType.STANDARD;

Expand Down Expand Up @@ -634,9 +631,8 @@ public void setSourceConfiguration(SourceConfiguration config)

updateFrequencies();

//Clear the tune channel object so that it can be recreated if the
//source configuration changes
mTunerChannel = null;
//Clear the tune channels object so that it can be recreated if the source configuration changes
mTunerChannels = null;
}

/**
Expand Down Expand Up @@ -680,35 +676,50 @@ public void setRecordConfiguration(RecordConfiguration config)
}

/**
* Convenience method to construct a tuner channel object representing a
* tuner or recording source frequency and bandwidth that can be used by
* application components for graphically representing this channel.
* Convenience method to construct a tuner channel object representing a tuner or recording source frequency and
* bandwidth that can be used by application components for graphically representing this channel.
*
* If the source configuration is not a tuner or recording, this method
* returns null.
* If the source configuration is not a tuner or recording, this method returns an empty list.
*/
@JsonIgnore
public TunerChannel getTunerChannel()
public List<TunerChannel> getTunerChannels()
{
if(mTunerChannel == null)
if(mTunerChannels == null && mSourceConfiguration != null)
{
if(mSourceConfiguration.getSourceType() == SourceType.TUNER)
{
SourceConfigTuner config = (SourceConfigTuner)mSourceConfiguration;
mTunerChannels = new ArrayList<>();

mTunerChannel = new TunerChannel(config.getFrequency(),
mDecodeConfiguration.getChannelSpecification().getBandwidth());
}
else if(mSourceConfiguration.getSourceType() == SourceType.RECORDING)
switch(mSourceConfiguration.getSourceType())
{
SourceConfigRecording config = (SourceConfigRecording)mSourceConfiguration;

mTunerChannel = new TunerChannel(config.getFrequency(),
mDecodeConfiguration.getChannelSpecification().getBandwidth());
case TUNER:
if(mSourceConfiguration instanceof SourceConfigTuner tunerConfig)
{
mTunerChannels.add(new TunerChannel(tunerConfig.getFrequency(),
mDecodeConfiguration.getChannelSpecification().getBandwidth()));
}
break;
case TUNER_MULTIPLE_FREQUENCIES:
if(mSourceConfiguration instanceof SourceConfigTunerMultipleFrequency multiConfig)
{
for(long frequency: multiConfig.getFrequencies())
{
mTunerChannels.add(new TunerChannel(frequency,
mDecodeConfiguration.getChannelSpecification().getBandwidth()));
}
}
break;
case RECORDING:
if(mSourceConfiguration instanceof SourceConfigRecording recordingConfig)
{
mTunerChannels.add(new TunerChannel(recordingConfig.getFrequency(),
mDecodeConfiguration.getChannelSpecification().getBandwidth()));
}
break;
default:
mLog.warn("Unrecognized channel source type: " + mSourceConfiguration.getSourceType());
}
}

return mTunerChannel;
return mTunerChannels;
}

/**
Expand All @@ -717,9 +728,15 @@ else if(mSourceConfiguration.getSourceType() == SourceType.RECORDING)
*/
public boolean isWithin(long minimum, long maximum)
{
TunerChannel tunerChannel = getTunerChannel();
for(TunerChannel tunerChannel: getTunerChannels())
{
if(tunerChannel.overlaps(minimum, maximum))
{
return true;
}
}

return tunerChannel != null && tunerChannel.overlaps(minimum, maximum);
return false;
}

/**
Expand Down
@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
* Copyright (C) 2014-2024 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
Expand Down Expand Up @@ -444,11 +444,11 @@ public void receive(ProcessingChain processingChain)

if(channel != null)
{
TunerChannel tunerChannel = channel.getTunerChannel();
List<TunerChannel> tunerChannels = channel.getTunerChannels();

if(tunerChannel != null)
if(!tunerChannels.isEmpty())
{
mFrequencyOverlayPanel.setChannelBandwidth(tunerChannel.getBandwidth());
mFrequencyOverlayPanel.setChannelBandwidth(tunerChannels.get(0).getBandwidth());
}
}
}
Expand Down
84 changes: 45 additions & 39 deletions src/main/java/io/github/dsheirer/spectrum/OverlayPanel.java
@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2023 Dennis Sheirer
* Copyright (C) 2014-2024 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
Expand Down Expand Up @@ -550,60 +550,63 @@ else if(channel.isProcessing())
graphics.setColor(mColorChannelConfig);
}

TunerChannel tunerChannel = channel.getTunerChannel();
List<TunerChannel> tunerChannels = channel.getTunerChannels();

if(tunerChannel != null)
for(TunerChannel tunerChannel: tunerChannels)
{
double xAxis = getAxisFromFrequency(tunerChannel.getFrequency());
if(tunerChannel.overlaps(getMinDisplayFrequency(), getMaxDisplayFrequency()))
{
double xAxis = getAxisFromFrequency(tunerChannel.getFrequency());

double width = (double)(tunerChannel.getBandwidth()) / (double)getDisplayBandwidth() * getSize().getWidth();
double width = (double)(tunerChannel.getBandwidth()) / (double)getDisplayBandwidth() * getSize().getWidth();

Rectangle2D.Double box =
new Rectangle2D.Double(xAxis - (width / 2.0d), 0.0d, width, getSize().getHeight() - mSpectrumInset);
Rectangle2D.Double box =
new Rectangle2D.Double(xAxis - (width / 2.0d), 0.0d, width, getSize().getHeight() - mSpectrumInset);

//Fill the box with the correct color
graphics.fill(box);
//Fill the box with the correct color
graphics.fill(box);

graphics.draw(box);
graphics.draw(box);

//Change to the line color to render the channel name, etc.
graphics.setColor(mColorSpectrumLine);
//Change to the line color to render the channel name, etc.
graphics.setColor(mColorSpectrumLine);

//Draw the labels starting at yAxis position 0
double yAxis = 0;
//Draw the labels starting at yAxis position 0
double yAxis = 0;

//Draw the system label and adjust the y-axis position
String system = channel.hasSystem() ? channel.getSystem() : " ";
//Draw the system label and adjust the y-axis position
String system = channel.hasSystem() ? channel.getSystem() : " ";

yAxis += drawLabel(graphics, system, this.getFont(), xAxis, yAxis, width);
yAxis += drawLabel(graphics, system, this.getFont(), xAxis, yAxis, width);

//Draw the site label and adjust the y-axis position
String site = channel.hasSite() ? channel.getSite() : " ";
//Draw the site label and adjust the y-axis position
String site = channel.hasSite() ? channel.getSite() : " ";

yAxis += drawLabel(graphics, site, this.getFont(), xAxis, yAxis, width);
yAxis += drawLabel(graphics, site, this.getFont(), xAxis, yAxis, width);

//Draw the channel label and adjust the y-axis position
yAxis += drawLabel(graphics, channel.getName(), this.getFont(), xAxis, yAxis, width);
//Draw the channel label and adjust the y-axis position
yAxis += drawLabel(graphics, channel.getName(), this.getFont(), xAxis, yAxis, width);

//Draw the decoder label
drawLabel(graphics, channel.getDecodeConfiguration().getDecoderType().getShortDisplayString(),
this.getFont(), xAxis, yAxis, width);
//Draw the decoder label
drawLabel(graphics, channel.getDecodeConfiguration().getDecoderType().getShortDisplayString(),
this.getFont(), xAxis, yAxis, width);

long frequency = tunerChannel.getFrequency();
long frequency = tunerChannel.getFrequency();

double frequencyAxis = getAxisFromFrequency(frequency);
double frequencyAxis = getAxisFromFrequency(frequency);

drawChannelCenterLine(graphics, frequencyAxis);

/* Draw Automatic Frequency Control line */
int correction = channel.getChannelFrequencyCorrection();
drawChannelCenterLine(graphics, frequencyAxis);

if(correction != 0)
{
long error = frequency + correction;
/* Draw Automatic Frequency Control line */
int correction = channel.getChannelFrequencyCorrection();

if(correction != 0)
{
long error = frequency + correction;

drawAFC(graphics, frequencyAxis, getAxisFromFrequency(error), width, correction,
tunerChannel.getFrequency());
drawAFC(graphics, frequencyAxis, getAxisFromFrequency(error), width, correction,
tunerChannel.getFrequency());
}
}
}
}
Expand Down Expand Up @@ -796,11 +799,14 @@ public ArrayList<Channel> getChannelsAtFrequency(long frequency)

for(Channel config : mVisibleChannels)
{
TunerChannel channel = config.getTunerChannel();
List<TunerChannel> channels = config.getTunerChannels();

if(channel != null && channel.getMinFrequency() <= frequency && channel.getMaxFrequency() >= frequency)
for(TunerChannel channel: channels)
{
configs.add(config);
if(channel != null && channel.getMinFrequency() <= frequency && channel.getMaxFrequency() >= frequency)
{
configs.add(config);
}
}
}

Expand Down

0 comments on commit 2c32096

Please sign in to comment.