Compare commits

...

17 Commits

Author SHA1 Message Date
Denny Sheirer
4cd8f8209f Merge pull request #216 from DSheirer/215-audio-recording-handles-part-2
215 audio recording handles part 2
2017-03-03 15:49:24 +00:00
Denny
61bfef5798 Incrementing build to version 0.3.0 beta8 2017-03-03 10:44:50 -05:00
Denny
ef172a04c6 Cleanup - removed synchronized blocks since the buffer processor thread is the only thread managing recorders. 2017-03-03 10:04:21 -05:00
Denny
a877afcceb Updates buffer processing in recorder manager so that we're not blocking any of the decoding channel producer threads that are trying to push audio packets to the recorder manager. Adds an overflowable packet queue and services the queue once a second followed by an idle recorder check (and disposal). 2017-03-03 10:01:32 -05:00
Denny
980ad72d4d Incrementing build to 0.3.0 beta7 2017-03-03 06:01:09 -05:00
Denny Sheirer
9b746cc032 Merge pull request #215 from DSheirer/198-audio-recorder-handles-left-open
Resolves issue audio recorders left open
2017-03-03 10:58:08 +00:00
Denny
f51ae0b5da Resolves issue with periodic instances of audio recorders not being shutdown correctly. Adds recorder monitor as a fail-safe to automatically shutdown recorders that don't receive an end-call indication. 2017-03-03 05:56:32 -05:00
Denny Sheirer
561078e9bf Merge pull request #214 from DSheirer/210-playlist-saving-all-times
Resolves issue with the playlist saving all of the time
2017-03-03 00:34:25 +00:00
Denny
e052b01f9b Resolves issue with the playlist saving all of the time due to audio streaming broadcast events. 2017-03-02 19:33:10 -05:00
Denny
09cf4fcfd7 Resolves issue with empty string list models in channel editor 2017-02-26 10:29:14 -05:00
Denny
5e731d0e9f Resolves issue with alias list and group combo box value editing. 2017-02-26 06:51:58 -05:00
Denny Sheirer
670a02b0ba Merge pull request #209 from DSheirer/153-cursor-frequency-artifacts
Resolves issue with spectral display rendering artifacts
2017-02-26 10:48:59 +00:00
Denny
9ef156b061 Resolves issue with spectral display rendering artifacts from cursor frequency readout when accessing menu items directly above the spectral display. 2017-02-26 05:47:26 -05:00
Denny
d9cf1b19f3 Removes assert() usage throughout project and replaces with Validate from apache commons. 2017-02-25 16:03:35 -05:00
Denny
a4a339b505 Resolves issue with FCD2 tuner frequency. 2017-02-25 14:58:51 -05:00
Denny
119370c46e Resolves issue with FCD2 tuner frequency. 2017-02-25 14:57:25 -05:00
Denny
4eb66e6045 Updated readme file with screen shot and link to new Version 0.3.0 user's manual. 2017-02-25 06:18:59 -05:00
31 changed files with 1371 additions and 1299 deletions

View File

@@ -2,18 +2,10 @@
A cross-platform java application for decoding, monitoring, recording and streaming trunked mobile and related radio protocols using Software Defined Radios (SDR).
* [Getting Started](https://github.com/DSheirer/sdrtrunk/wiki/GettingStarted)
* [User's Manual](https://github.com/DSheirer/sdrtrunk/wiki/UserManual)
* [User's Manual Version 0.2.0](https://github.com/DSheirer/sdrtrunk/wiki/UserManual)
* [User's Manual Version 0.3.0](https://github.com/DSheirer/sdrtrunk/wiki/UserManual_Version0.3.0)
* [Download](https://github.com/DSheirer/sdrtrunk/releases)
* [Support](https://groups.google.com/forum/#!forum/sdrtrunk)
![](https://github.com/DSheirer/sdrtrunk/wiki/images/SDRTrunk_application.png)
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-67489234-1', 'auto');
ga('send', 'pageview');
</script>
![sdrtrunk Application Overview - Version 0.3.0](https://github.com/DSheirer/sdrtrunk/wiki/images/ApplicationOverview_V0.3.0.png)
**Figure 1:** sdrtrunk **Version 0.3.0** Application Screenshot

View File

@@ -7,7 +7,7 @@
<property name="major" value="0"/>
<property name="minor" value="3"/>
<property name="patch" value="0"/>
<property name="release" value="-beta6"/>
<property name="release" value="-beta8"/>
<property name="filename" value="sdrtrunk_${major}.${minor}.${patch}${release}"/>
<!-- Build properties -->

View File

@@ -40,10 +40,11 @@ public class AliasNameEditor extends Editor<Alias>
{
private static final long serialVersionUID = 1L;
private static ComboBoxModel<String> EMPTY_MODEL = new DefaultComboBoxModel<>();
private static ComboBoxModel<String> EMPTY_LIST_MODEL = new DefaultComboBoxModel<>();
private static ComboBoxModel<String> EMPTY_GROUP_MODEL = new DefaultComboBoxModel<>();
private JComboBox<String> mListCombo = new JComboBox<>(EMPTY_MODEL);
private JComboBox<String> mGroupCombo = new JComboBox<>(EMPTY_MODEL);
private JComboBox<String> mListCombo = new JComboBox<>(EMPTY_LIST_MODEL);
private JComboBox<String> mGroupCombo = new JComboBox<>(EMPTY_GROUP_MODEL);
private JComboBox<Icon> mIconCombo;
private JTextField mName;
private JButton mButtonColor;
@@ -110,7 +111,7 @@ public class AliasNameEditor extends Editor<Alias>
if(groups.isEmpty())
{
mGroupCombo.setModel(EMPTY_MODEL);
mGroupCombo.setModel(EMPTY_GROUP_MODEL);
}
else
{
@@ -238,7 +239,7 @@ public class AliasNameEditor extends Editor<Alias>
if(listNames.isEmpty())
{
mListCombo.setModel(EMPTY_MODEL);
mListCombo.setModel(EMPTY_LIST_MODEL);
}
else
{
@@ -253,7 +254,7 @@ public class AliasNameEditor extends Editor<Alias>
if(groupNames.isEmpty())
{
mGroupCombo.setModel(EMPTY_MODEL);
mGroupCombo.setModel(EMPTY_GROUP_MODEL);
}
else
{
@@ -285,8 +286,8 @@ public class AliasNameEditor extends Editor<Alias>
}
else
{
mListCombo.setModel(EMPTY_MODEL);
mGroupCombo.setModel(EMPTY_MODEL);
mListCombo.setModel(EMPTY_LIST_MODEL);
mGroupCombo.setModel(EMPTY_GROUP_MODEL);
mName.setText(null);
mButtonColor.setBackground(getBackground());

View File

@@ -18,6 +18,8 @@
******************************************************************************/
package alias.id;
import org.apache.commons.lang3.Validate;
import java.util.regex.Pattern;
public class WildcardID implements Comparable<WildcardID>
@@ -45,7 +47,7 @@ public class WildcardID implements Comparable<WildcardID>
*/
public WildcardID(String value)
{
assert(value != null && value.contains(WILDCARD) && value.length() < 10);
Validate.isTrue(value != null && value.contains(WILDCARD) && value.length() < 10);
mValue = value;

View File

@@ -21,6 +21,7 @@ package audio.broadcast.shoutcast.v2;
import audio.broadcast.BroadcastConfiguration;
import audio.broadcast.BroadcastFormat;
import audio.broadcast.BroadcastServerType;
import org.apache.commons.lang3.Validate;
import javax.xml.bind.annotation.XmlAttribute;
@@ -90,7 +91,7 @@ public class ShoutcastV2Configuration extends BroadcastConfiguration
*/
public void setStreamID(int streamID)
{
assert(1 <= streamID && streamID <= Integer.MAX_VALUE);
Validate.isTrue(1 <= streamID && streamID <= Integer.MAX_VALUE);
mStreamID = streamID;
}

View File

@@ -18,6 +18,8 @@
******************************************************************************/
package audio.broadcast.shoutcast.v2.ultravox;
import org.apache.commons.lang3.Validate;
public class NegotiateMaxPayloadSize extends UltravoxMessage
{
/**
@@ -47,8 +49,8 @@ public class NegotiateMaxPayloadSize extends UltravoxMessage
*/
public void setMaximumPayloadSize(int desiredMaximum, int minimum)
{
assert(desiredMaximum <= 16377);
assert(minimum <= 16377);
Validate.isTrue(desiredMaximum <= 16377);
Validate.isTrue(minimum <= 16377);
StringBuilder sb = new StringBuilder();
sb.append(desiredMaximum).append(":").append(minimum);

View File

@@ -19,6 +19,7 @@
package audio.broadcast.shoutcast.v2.ultravox;
import bits.BinaryMessage;
import org.apache.commons.lang3.Validate;
import java.util.Arrays;
@@ -154,7 +155,7 @@ public abstract class UltravoxMessage
*/
public void setSendQueuePriority(int priority)
{
assert(0 <= priority && priority <= 7);
Validate.isTrue(0 <= priority && priority <= 7);
mMessage.setInt(priority, SEND_QUEUE_PRIORITY);
}

View File

@@ -22,6 +22,7 @@ import java.util.BitSet;
import java.util.logging.LogManager;
import edac.CRC;
import org.apache.commons.lang3.Validate;
public class BinaryMessage extends BitSet
{
@@ -456,7 +457,7 @@ public class BinaryMessage extends BitSet
*/
public byte getByte(int index)
{
assert((index + 7) <= size());
Validate.isTrue((index + 7) <= size());
int value = 0;
@@ -481,7 +482,7 @@ public class BinaryMessage extends BitSet
*/
public void setByte(int index, byte value)
{
assert((index + 8) <= size());
Validate.isTrue((index + 8) <= size());
int mask = 0x80;

View File

@@ -17,6 +17,8 @@
******************************************************************************/
package bits;
import org.apache.commons.lang3.Validate;
import java.util.ArrayList;
import java.util.List;
@@ -39,7 +41,7 @@ public class MultiSyncPatternMatcher
public MultiSyncPatternMatcher( int syncSize )
{
assert( syncSize < 64 );
Validate.isTrue(syncSize < 64);
//Setup a bit mask of all ones the length of the sync pattern
mMask = (long)( ( Math.pow( 2, syncSize ) ) - 1 );

View File

@@ -26,6 +26,7 @@ import controller.channel.ChannelUtils;
import icon.IconManager;
import module.ProcessingChain;
import net.miginfocom.swing.MigLayout;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import properties.SystemProperties;
@@ -140,7 +141,7 @@ public class ChannelMetadataPanel extends JPanel implements ListSelectionListene
public AliasedValueCellRenderer(Attribute attribute)
{
assert(attribute != null);
Validate.isTrue(attribute != null);
mAttribute = attribute;
setHorizontalAlignment(JLabel.CENTER);
}

View File

@@ -1,269 +1,267 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 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 controller.channel;
import alias.AliasModel;
import gui.editor.Editor;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collections;
import java.util.List;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.miginfocom.swing.MigLayout;
import alias.AliasModel;
public class NameConfigurationEditor extends Editor<Channel> implements DocumentListener
{
private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 1L;
private final static Logger mLog = LoggerFactory.getLogger( NameConfigurationEditor.class );
private final static Logger mLog = LoggerFactory.getLogger(NameConfigurationEditor.class);
private static ComboBoxModel<String> EMPTY_MODEL = new DefaultComboBoxModel<>();
private static ComboBoxModel<String> EMPTY_SYSTEM_MODEL = new DefaultComboBoxModel<>();
private static ComboBoxModel<String> EMPTY_SITE_MODEL = new DefaultComboBoxModel<>();
private static ComboBoxModel<String> EMPTY_ALIAS_LIST_MODEL = new DefaultComboBoxModel<>();
private AliasModel mAliasModel;
private ChannelModel mChannelModel;
private JTextField mChannelName;
private JComboBox<String> mSystemNameCombo;
private JComboBox<String> mSiteNameCombo;
private JComboBox<String> mAliasListCombo;
public NameConfigurationEditor( AliasModel aliasModel, ChannelModel model )
{
mAliasModel = aliasModel;
mChannelModel = model;
private AliasModel mAliasModel;
private ChannelModel mChannelModel;
init();
}
private void init()
{
setLayout( new MigLayout( "fill,wrap 4", "[right][grow,fill][right][grow,fill]", "[][][grow]" ) );
private JTextField mChannelName;
private JComboBox<String> mSystemNameCombo;
private JComboBox<String> mSiteNameCombo;
private JComboBox<String> mAliasListCombo;
mChannelName = new JTextField( "" );
mChannelName.getDocument().addDocumentListener( this );
mChannelName.setEnabled( false );
public NameConfigurationEditor(AliasModel aliasModel, ChannelModel model)
{
mAliasModel = aliasModel;
mChannelModel = model;
add( new JLabel( "Name:" ) );
add( mChannelName );
init();
}
mSystemNameCombo = new JComboBox<>( EMPTY_MODEL );
mSystemNameCombo.setEnabled( false );
mSystemNameCombo.setEditable( true );
mSystemNameCombo.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
Object selected = mSystemNameCombo.getSelectedItem();
if( selected != null )
{
String system = (String)selected;
List<String> sites = mChannelModel.getSites( system );
private void init()
{
setLayout(new MigLayout("fill,wrap 4", "[right][grow,fill][right][grow,fill]", "[][][grow]"));
if( !sites.contains( getItem().getSite() ) )
{
sites.add( getItem().getSite() );
}
if( sites.isEmpty() )
{
mSiteNameCombo.setModel( EMPTY_MODEL );
}
else
{
mSiteNameCombo.setModel( new DefaultComboBoxModel<String>(
sites.toArray( new String[ sites.size() ] ) ) );;
}
mSiteNameCombo.setSelectedItem( getItem().getSite() );
}
setModified( true );
}
} );
add( new JLabel( "System:" ) );
add( mSystemNameCombo );
mChannelName = new JTextField("");
mChannelName.getDocument().addDocumentListener(this);
mChannelName.setEnabled(false);
mAliasListCombo = new JComboBox<String>();
mAliasListCombo.setEnabled( false );
mAliasListCombo.setEditable( true );
mAliasListCombo.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
setModified( true );
}
} );
add( new JLabel( "Alias List:" ) );
add( mAliasListCombo );
mSiteNameCombo = new JComboBox<>( EMPTY_MODEL );
mSiteNameCombo.setEnabled( false );
mSiteNameCombo.setEditable( true );
mSiteNameCombo.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
setModified( true );
}
} );
add( new JLabel( "Site:" ) );
add( mSiteNameCombo );
}
@Override
public void save()
{
if( hasItem() && isModified() )
{
getItem().setName( mChannelName.getText() );
Object system = mSystemNameCombo.getSelectedItem();
getItem().setSystem( ( system == null ? null : (String)system ) );
add(new JLabel("Name:"));
add(mChannelName);
Object site = mSiteNameCombo.getSelectedItem();
getItem().setSite( ( site == null ? null : (String)site ) );
mSystemNameCombo = new JComboBox<>(EMPTY_SYSTEM_MODEL);
mSystemNameCombo.setEnabled(false);
mSystemNameCombo.setEditable(true);
mSystemNameCombo.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
Object selected = mSystemNameCombo.getSelectedItem();
Object aliasList = mAliasListCombo.getSelectedItem();
getItem().setAliasListName( aliasList == null ? null : (String)aliasList );
}
setModified( false );
}
if(selected != null)
{
String system = (String)selected;
private void setControlsEnabled( boolean enabled )
{
if( mChannelName.isEnabled() != enabled )
{
mChannelName.setEnabled( enabled );
}
List<String> sites = mChannelModel.getSites(system);
if( mAliasListCombo.isEnabled() != enabled )
{
mAliasListCombo.setEnabled( enabled );
}
if(!sites.contains(getItem().getSite()))
{
sites.add(getItem().getSite());
}
if( mSystemNameCombo.isEnabled() != enabled )
{
mSystemNameCombo.setEnabled( enabled );
}
if( mSiteNameCombo.isEnabled() != enabled )
{
mSiteNameCombo.setEnabled( enabled );
}
}
if(sites.isEmpty())
{
mSiteNameCombo.setModel(EMPTY_SITE_MODEL);
}
else
{
mSiteNameCombo.setModel(new DefaultComboBoxModel<String>(
sites.toArray(new String[sites.size()])));
;
}
@Override
public void setItem( Channel channel )
{
super.setItem( channel );
if( hasItem() )
{
setControlsEnabled( true );
mChannelName.setText( channel.getName() );
mSiteNameCombo.setSelectedItem(getItem().getSite());
}
List<String> systems = mChannelModel.getSystems();
if( systems.isEmpty() )
{
mSystemNameCombo.setModel( EMPTY_MODEL );
}
else
{
mSystemNameCombo.setModel( new DefaultComboBoxModel<String>(
systems.toArray( new String[ systems.size() ] ) ) );;
}
mSystemNameCombo.setSelectedItem( channel.getSystem() );
setModified(true);
}
});
List<String> sites = mChannelModel.getSites( channel.getSystem() );
add(new JLabel("System:"));
add(mSystemNameCombo);
if( sites.isEmpty() )
{
mSiteNameCombo.setModel( EMPTY_MODEL );
}
else
{
mSiteNameCombo.setModel( new DefaultComboBoxModel<String>(
sites.toArray( new String[ sites.size() ] ) ) );;
}
mAliasListCombo = new JComboBox<String>(EMPTY_ALIAS_LIST_MODEL);
mAliasListCombo.setEnabled(false);
mAliasListCombo.setEditable(true);
mAliasListCombo.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
setModified(true);
}
});
if( channel.getSite() != null )
{
mSiteNameCombo.setSelectedItem( channel.getSite() );
}
List<String> lists = mAliasModel.getListNames();
Collections.sort( lists );
mAliasListCombo.setModel( new DefaultComboBoxModel<String>(
lists.toArray( new String[ lists.size() ] ) ) );
if( channel.getAliasListName() != null )
{
mAliasListCombo.setSelectedItem( channel.getAliasListName() );
}
}
else
{
setControlsEnabled( false );
mChannelName.setText( null );
}
setModified( false );
}
add(new JLabel("Alias List:"));
add(mAliasListCombo);
@Override
public void insertUpdate( DocumentEvent e )
{
setModified( true );
}
mSiteNameCombo = new JComboBox<>(EMPTY_SITE_MODEL);
mSiteNameCombo.setEnabled(false);
mSiteNameCombo.setEditable(true);
mSiteNameCombo.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
setModified(true);
}
});
@Override
public void changedUpdate( DocumentEvent e )
{
setModified( true );
}
@Override
public void removeUpdate( DocumentEvent e )
{
setModified( true );
}
add(new JLabel("Site:"));
add(mSiteNameCombo);
}
@Override
public void save()
{
if(hasItem() && isModified())
{
getItem().setName(mChannelName.getText());
Object system = mSystemNameCombo.getSelectedItem();
getItem().setSystem((system == null ? null : (String)system));
Object site = mSiteNameCombo.getSelectedItem();
getItem().setSite((site == null ? null : (String)site));
Object aliasList = mAliasListCombo.getSelectedItem();
getItem().setAliasListName(aliasList == null ? null : (String)aliasList);
}
setModified(false);
}
private void setControlsEnabled(boolean enabled)
{
if(mChannelName.isEnabled() != enabled)
{
mChannelName.setEnabled(enabled);
}
if(mAliasListCombo.isEnabled() != enabled)
{
mAliasListCombo.setEnabled(enabled);
}
if(mSystemNameCombo.isEnabled() != enabled)
{
mSystemNameCombo.setEnabled(enabled);
}
if(mSiteNameCombo.isEnabled() != enabled)
{
mSiteNameCombo.setEnabled(enabled);
}
}
@Override
public void setItem(Channel channel)
{
super.setItem(channel);
if(hasItem())
{
setControlsEnabled(true);
mChannelName.setText(channel.getName());
List<String> systems = mChannelModel.getSystems();
if(systems.isEmpty())
{
mSystemNameCombo.setModel(EMPTY_SYSTEM_MODEL);
}
else
{
mSystemNameCombo.setModel(new DefaultComboBoxModel<String>(
systems.toArray(new String[systems.size()])));
;
}
mSystemNameCombo.setSelectedItem(channel.getSystem());
List<String> sites = mChannelModel.getSites(channel.getSystem());
if(sites.isEmpty())
{
mSiteNameCombo.setModel(EMPTY_SITE_MODEL);
}
else
{
mSiteNameCombo.setModel(new DefaultComboBoxModel<String>(
sites.toArray(new String[sites.size()])));
;
}
if(channel.getSite() != null)
{
mSiteNameCombo.setSelectedItem(channel.getSite());
}
List<String> lists = mAliasModel.getListNames();
Collections.sort(lists);
mAliasListCombo.setModel(new DefaultComboBoxModel<String>(
lists.toArray(new String[lists.size()])));
if(channel.getAliasListName() != null)
{
mAliasListCombo.setSelectedItem(channel.getAliasListName());
}
}
else
{
setControlsEnabled(false);
mChannelName.setText(null);
}
setModified(false);
}
@Override
public void insertUpdate(DocumentEvent e)
{
setModified(true);
}
@Override
public void changedUpdate(DocumentEvent e)
{
setModified(true);
}
@Override
public void removeUpdate(DocumentEvent e)
{
setModified(true);
}
}

View File

@@ -19,6 +19,7 @@ package dsp.filter;
import java.util.ArrayList;
import org.apache.commons.lang3.Validate;
import sample.real.RealSampleListener;
public class FloatFIRFilter implements RealSampleListener
@@ -139,7 +140,7 @@ public class FloatFIRFilter implements RealSampleListener
private void generateIndexMap( int size )
{
//Ensure we have an odd size
assert( size % 2 == 1 );
Validate.isTrue(size % 2 == 1);
mIndexMap = new int[ size ][ size ];

View File

@@ -19,6 +19,7 @@ package dsp.filter;
import java.util.ArrayList;
import org.apache.commons.lang3.Validate;
import sample.real.RealSampleListener;
public class FloatHalfBandFilter implements RealSampleListener
@@ -149,7 +150,7 @@ public class FloatHalfBandFilter implements RealSampleListener
private void generateIndexMap( int size )
{
//Ensure we have an odd size
assert( size % 2 == 1 );
Validate.isTrue(size % 2 == 1);
int mapWidth = ( ( size + 1 ) / 2 ) + 1;

View File

@@ -19,6 +19,7 @@ package dsp.filter;
import java.util.ArrayList;
import org.apache.commons.lang3.Validate;
import sample.real.RealSampleListener;
public class FloatHalfBandNoDecimateFilter implements RealSampleListener
@@ -139,7 +140,7 @@ public class FloatHalfBandNoDecimateFilter implements RealSampleListener
private void generateIndexMap( int size )
{
//Ensure we have an odd size
assert( size % 2 == 1 );
Validate.isTrue(size % 2 == 1);
int mapWidth = ( ( size + 1 ) / 2 ) + 1;

View File

@@ -20,6 +20,7 @@ package dsp.filter.cic;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.Validate;
import sample.Listener;
import sample.complex.ComplexBuffer;
import sample.complex.ComplexSampleListener;
@@ -67,7 +68,7 @@ public class ComplexPrimeCICDecimate implements Listener<ComplexBuffer>
public ComplexPrimeCICDecimate( int decimation, int order,
int passFrequency, int attenuation, WindowType windowType )
{
assert( decimation <= 700 );
Validate.isTrue(decimation <= 700);
List<Integer> stageSizes = getPrimeFactors( decimation );

View File

@@ -20,6 +20,7 @@ package dsp.filter.cic;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -81,7 +82,7 @@ public class RealPrimeCICDecimate
public RealPrimeCICDecimate( int decimation, int order, int passFrequency,
int attenuation, WindowType windowType, int outputBufferSize )
{
assert( decimation <= 700 );
Validate.isTrue(decimation <= 700);
mOutputBufferSize = outputBufferSize;

View File

@@ -17,6 +17,8 @@
******************************************************************************/
package dsp.filter.halfband.real;
import org.apache.commons.lang3.Validate;
public class HalfBandFilter
{
private float[] mBuffer;
@@ -122,7 +124,7 @@ public class HalfBandFilter
private void generateIndexMap( int size )
{
//Ensure we have an odd size
assert( size % 2 == 1 );
Validate.isTrue(size % 2 == 1);
int mapWidth = ( ( size + 1 ) / 2 ) + 1;

View File

@@ -1,5 +1,6 @@
package dsp.filter.interpolator;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -31,7 +32,7 @@ public class RealInterpolator extends Interpolator
public float filter( float[] samples, int offset, float mu )
{
/* Ensure we have enough samples in the array */
assert( samples.length >= offset + 7 );
Validate.isTrue(samples.length >= offset + 7);
/* Identify the filter bank that corresponds to mu */
int index = (int)( NSTEPS * mu );

View File

@@ -18,6 +18,7 @@
******************************************************************************/
package dsp.filter.polyphase;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -53,7 +54,7 @@ public class PolyphaseFIRInterpolatingFilter
public PolyphaseFIRInterpolatingFilter( double[] coefficients, int interpolation )
{
/* Ensure coefficients are an integral multiple of the interpolation factor */
assert( coefficients.length % interpolation == 0 );
Validate.isTrue(coefficients.length % interpolation == 0);
mTaps = coefficients;

View File

@@ -17,6 +17,7 @@
******************************************************************************/
package dsp.gain;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -49,7 +50,7 @@ public class DirectGainControl implements GainController, RealSampleListener
*/
public DirectGainControl( float gain, float minimum, float maximum, float increment )
{
assert( minimum > 0 );
Validate.isTrue(minimum > 0);
mDefaultGain = gain;
mGain = gain;

View File

@@ -89,6 +89,7 @@ public class PlaylistManager implements ChannelEventListener
@Override
public void receive(AliasEvent t)
{
//Save the playlist for all alias events
schedulePlaylistSave();
}
});
@@ -98,6 +99,7 @@ public class PlaylistManager implements ChannelEventListener
@Override
public void receive(ChannelMapEvent t)
{
//Save the playlist for all channel map events
schedulePlaylistSave();
}
});
@@ -107,7 +109,23 @@ public class PlaylistManager implements ChannelEventListener
@Override
public void receive(BroadcastEvent broadcastEvent)
{
schedulePlaylistSave();
switch(broadcastEvent.getEvent())
{
case CONFIGURATION_ADD:
case CONFIGURATION_CHANGE:
case CONFIGURATION_DELETE:
schedulePlaylistSave();
break;
case BROADCASTER_ADD:
case BROADCASTER_QUEUE_CHANGE:
case BROADCASTER_STATE_CHANGE:
case BROADCASTER_STREAMED_COUNT_CHANGE:
case BROADCASTER_AGED_OFF_COUNT_CHANGE:
case BROADCASTER_DELETE:
default:
//Do nothing
break;
}
}
});
}

View File

@@ -25,87 +25,169 @@ import properties.SystemProperties;
import record.wave.ComplexBufferWaveRecorder;
import record.wave.RealBufferWaveRecorder;
import sample.Listener;
import sample.OverflowableTransferQueue;
import sample.real.IOverflowListener;
import util.ThreadPool;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class RecorderManager implements Listener<AudioPacket>
{
private static final Logger mLog = LoggerFactory.getLogger(RecorderManager.class);
public static final int AUDIO_SAMPLE_RATE = 8000;
public static final long IDLE_RECORDER_REMOVAL_THRESHOLD = 6000; //6 seconds
private Map<String,RealBufferWaveRecorder> mRecorders = new HashMap<>();
private OverflowableTransferQueue<AudioPacket> mAudioPacketQueue = new OverflowableTransferQueue<>(1000, 100);
private ScheduledFuture<?> mBufferProcessorFuture;
private boolean mCanStartNewRecorders = true;
/**
* Manages all audio recording for all processing channels. Reconstructs audio streams and distributes channel
* audio to each of the recorders, starting and stopping the recorders as needed.
* Audio recording manager. Monitors stream of audio packets produced by decoding channels and automatically starts
* audio recorders when the channel's metadata designates a call as recordable. Routes call audio to each recorder
* based on audio packet metadata. Recorders are shutdown when the channel sends an end-call audio packet
* indicating that the call is complete. A separate recording monitor periodically checks for idled recorders to
* be stopped for cases when the channel fails to send an end-call audio packet.
*/
public RecorderManager()
{
mAudioPacketQueue.setOverflowListener(new IOverflowListener()
{
@Override
public void sourceOverflow(boolean overflow)
{
if(overflow)
{
mLog.warn("overflow - audio packets will be dropped until recording catches up");
}
else
{
mLog.info("audio recorder packet processing has returned to normal");
}
}
});
mBufferProcessorFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(new BufferProcessor(), 0,
1, TimeUnit.SECONDS);
}
/**
* Prepares this class for shutdown
*/
public void dispose()
{
if(mBufferProcessorFuture != null)
{
mBufferProcessorFuture.cancel(true);
}
}
/**
* Primary ingest point for audio packets from all decoding channels
* @param audioPacket to process
*/
@Override
public void receive(AudioPacket audioPacket)
{
if(audioPacket.hasMetadata() &&
audioPacket.getMetadata().isRecordable())
if(audioPacket.hasMetadata() && audioPacket.getMetadata().isRecordable())
{
String identifier = audioPacket.getMetadata().getUniqueIdentifier();
mAudioPacketQueue.offer(audioPacket);
}
}
if(mRecorders.containsKey(identifier))
/**
* Process any queued audio buffers and dispatch them to the audio recorders
*/
private void processBuffers()
{
List<AudioPacket> audioPackets = new ArrayList<>();
mAudioPacketQueue.drainTo(audioPackets, 50);
while(!audioPackets.isEmpty())
{
for(AudioPacket audioPacket: audioPackets)
{
RealBufferWaveRecorder recorder = mRecorders.get(identifier);
String identifier = audioPacket.getMetadata().getUniqueIdentifier();
if(audioPacket.getType() == AudioPacket.Type.AUDIO)
if(mRecorders.containsKey(identifier))
{
recorder.receive(audioPacket.getAudioBuffer());
}
else if(audioPacket.getType() == AudioPacket.Type.END)
{
RealBufferWaveRecorder finished = mRecorders.remove(identifier);
finished.stop();
}
}
else if(audioPacket.getType() == AudioPacket.Type.AUDIO)
{
if(mCanStartNewRecorders)
{
String filePrefix = getFilePrefix(audioPacket);
RealBufferWaveRecorder recorder = mRecorders.get(identifier);
RealBufferWaveRecorder recorder = null;
try
if(audioPacket.getType() == AudioPacket.Type.AUDIO)
{
recorder = new RealBufferWaveRecorder(AUDIO_SAMPLE_RATE, filePrefix);
recorder.start(ThreadPool.SCHEDULED);
recorder.receive(audioPacket.getAudioBuffer());
mRecorders.put(identifier, recorder);
}
catch(Exception ioe)
else if(audioPacket.getType() == AudioPacket.Type.END)
{
mCanStartNewRecorders = false;
RealBufferWaveRecorder finished = mRecorders.remove(identifier);
finished.stop();
}
}
else if(audioPacket.getType() == AudioPacket.Type.AUDIO)
{
if(mCanStartNewRecorders)
{
String filePrefix = getFilePrefix(audioPacket);
mLog.error("Error attempting to start new audio wave recorder. All (future) audio recording " +
"is disabled", ioe);
RealBufferWaveRecorder recorder = null;
if(recorder != null)
try
{
recorder.stop();
recorder = new RealBufferWaveRecorder(AUDIO_SAMPLE_RATE, filePrefix);
recorder.start(ThreadPool.SCHEDULED);
recorder.receive(audioPacket.getAudioBuffer());
mRecorders.put(identifier, recorder);
}
catch(Exception ioe)
{
mCanStartNewRecorders = false;
mLog.error("Error attempting to start new audio wave recorder. All (future) audio recording " +
"is disabled", ioe);
if(recorder != null)
{
recorder.stop();
}
}
}
}
}
audioPackets.clear();
mAudioPacketQueue.drainTo(audioPackets, 50);
}
}
/**
* Removes recorders that have not received any new audio buffers in the last 6 seconds.
*/
private void removeIdleRecorders()
{
Iterator<Map.Entry<String,RealBufferWaveRecorder>> it = mRecorders.entrySet().iterator();
while(it.hasNext())
{
Map.Entry<String,RealBufferWaveRecorder> entry = it.next();
if(entry.getValue().getLastBufferReceived() + IDLE_RECORDER_REMOVAL_THRESHOLD < System.currentTimeMillis())
{
mLog.info("Removing idle recorder [" + entry.getKey() + "]");
it.remove();
entry.getValue().stop();
}
}
}
@@ -150,4 +232,18 @@ public class RecorderManager implements Listener<AudioPacket>
return new ComplexBufferWaveRecorder(AUDIO_SAMPLE_RATE, sb.toString());
}
/**
* Processes queued audio packets and distributes to each of the audio recorders. Removes any idle recorders
* that have not been updated according to an idle threshold period
*/
public class BufferProcessor implements Runnable
{
@Override
public void run()
{
processBuffers();
removeIdleRecorders();
}
}
}

View File

@@ -18,6 +18,7 @@
******************************************************************************/
package record.wave;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.ConversionUtils;
@@ -58,7 +59,7 @@ public class MonoWaveReader implements AutoCloseable
*/
public MonoWaveReader(Path path, boolean realTime) throws IOException
{
assert( path != null );
Validate.isTrue(path != null);
mPath = path;
mRealTime = realTime;

View File

@@ -1,22 +1,33 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014,2015 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/>
* sdrtrunk
* Copyright (C) 2014-2017 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 record.wave;
import module.Module;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.ConversionUtils;
import sample.Listener;
import sample.real.IFilteredRealBufferListener;
import sample.real.RealBuffer;
import util.TimeStamp;
import javax.sound.sampled.AudioFormat;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -26,206 +37,175 @@ import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.sound.sampled.AudioFormat;
import module.Module;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.ConversionUtils;
import sample.Listener;
import sample.real.IFilteredRealBufferListener;
import sample.real.RealBuffer;
import util.TimeStamp;
/**
* WAVE audio recorder module for recording real sample buffers to a wave file
*/
public class RealBufferWaveRecorder extends Module
implements IFilteredRealBufferListener, Listener<RealBuffer>
public class RealBufferWaveRecorder extends Module
implements IFilteredRealBufferListener, Listener<RealBuffer>
{
private final static Logger mLog =
LoggerFactory.getLogger( RealBufferWaveRecorder.class );
private final static Logger mLog = LoggerFactory.getLogger(RealBufferWaveRecorder.class);
private WaveWriter mWriter;
private String mFilePrefix;
private Path mFile;
private AudioFormat mAudioFormat;
private BufferProcessor mBufferProcessor;
private ScheduledFuture<?> mProcessorHandle;
private LinkedBlockingQueue<RealBuffer> mBuffers =
new LinkedBlockingQueue<>( 500 );
private long mLastBufferReceived;
private AtomicBoolean mRunning = new AtomicBoolean();
public RealBufferWaveRecorder( int sampleRate, String filePrefix )
{
mAudioFormat = new AudioFormat( sampleRate, //SampleRate
16, //Sample Size
1, //Channels
true, //Signed
false ); //Little Endian
private AudioFormat mAudioFormat;
mFilePrefix = filePrefix;
}
private BufferProcessor mBufferProcessor;
private ScheduledFuture<?> mProcessorHandle;
private LinkedBlockingQueue<RealBuffer> mBuffers = new LinkedBlockingQueue<>(500);
private long mLastBufferReceived;
/**
* Timestamp of when the latest buffer was received by this recorder
*/
public long getLastBufferReceived()
{
return mLastBufferReceived;
}
private AtomicBoolean mRunning = new AtomicBoolean();
public Path getFile()
{
return mFile;
}
public void start( ScheduledExecutorService executor )
{
if( mRunning.compareAndSet( false, true ) )
{
if( mBufferProcessor == null )
{
mBufferProcessor = new BufferProcessor();
}
public RealBufferWaveRecorder(int sampleRate, String filePrefix)
{
mAudioFormat = new AudioFormat(sampleRate, //SampleRate
16, //Sample Size
1, //Channels
true, //Signed
false); //Little Endian
try
{
StringBuilder sb = new StringBuilder();
sb.append( mFilePrefix );
sb.append( "_" );
sb.append( TimeStamp.getLongTimeStamp( "_" ) );
sb.append( ".wav" );
mFile = Paths.get( sb.toString() );
mFilePrefix = filePrefix;
}
mWriter = new WaveWriter( mAudioFormat, mFile );
/**
* Indicates if the recorder is currently running.
*/
public boolean isRunning()
{
return mRunning.get();
}
/**
* Timestamp of when the latest buffer was received by this recorder
*/
public long getLastBufferReceived()
{
return mLastBufferReceived;
}
public Path getFile()
{
return mFile;
}
public void start(ScheduledExecutorService executor)
{
if(mRunning.compareAndSet(false, true))
{
if(mBufferProcessor == null)
{
mBufferProcessor = new BufferProcessor();
}
try
{
StringBuilder sb = new StringBuilder();
sb.append(mFilePrefix);
sb.append("_");
sb.append(TimeStamp.getLongTimeStamp("_"));
sb.append(".wav");
mFile = Paths.get(sb.toString());
mWriter = new WaveWriter(mAudioFormat, mFile);
/* Schedule the processor to run every 500 milliseconds */
mProcessorHandle = executor.scheduleAtFixedRate(
mBufferProcessor, 0, 500, TimeUnit.MILLISECONDS );
}
catch( IOException io )
{
mLog.error( "Error starting real buffer recorder", io );
}
}
}
public void stop()
{
/* Signal the buffer processor to end with a poison pill */
receive( new PoisonPill() );
mRunning.set( false );
}
@Override
public void receive( RealBuffer buffer )
{
if( mRunning.get() )
{
boolean success = mBuffers.offer( buffer );
if( !success )
{
mLog.error( "recorder buffer overflow - purging [" +
mFile.toFile().getAbsolutePath() + "]" );
mBuffers.clear();
}
mLastBufferReceived = System.currentTimeMillis();
}
}
@Override
public Listener<RealBuffer> getFilteredRealBufferListener()
{
return this;
}
@Override
public void dispose()
{
stop();
}
@Override
public void reset()
{
}
public class BufferProcessor implements Runnable
{
public void run()
{
try
{
RealBuffer buffer = mBuffers.poll();
while( buffer != null )
{
if( buffer instanceof PoisonPill )
{
buffer = null;
mBuffers.clear();
if( mWriter != null )
{
try
{
mWriter.close();
}
catch( IOException io )
{
mLog.error( "Error stopping complex wave recorder [" +
getFile() + "]", io );
}
}
if( mProcessorHandle != null )
{
mProcessorHandle.cancel( true );
}
mProcessorHandle = null;
mWriter = null;
mFile = null;
}
else
{
mWriter.write( ConversionUtils.convertToSigned16BitSamples( buffer ) );
buffer = mBuffers.poll();
}
}
mProcessorHandle = executor.scheduleAtFixedRate(mBufferProcessor, 0, 500, TimeUnit.MILLISECONDS);
}
catch ( IOException ioe )
{
/* Stop this module if/when we get an IO exception */
mBuffers.clear();
stop();
mLog.error( "IOException while trying to write to the wave "
+ "writer", ioe );
}
}
catch(IOException io)
{
mLog.error("Error starting real buffer recorder", io);
}
}
}
public void stop()
{
if(mRunning.compareAndSet(true, false))
{
try
{
write();
if(mWriter != null)
{
mWriter.close();
mWriter = null;
}
}
catch(IOException ioe)
{
mLog.error("Error writing final audio buffers to recording during shutdown", ioe);
}
}
}
@Override
public void receive(RealBuffer buffer)
{
if(mRunning.get())
{
boolean success = mBuffers.offer(buffer);
if(!success)
{
mLog.error("recorder buffer overflow - purging [" + mFile.toFile().getAbsolutePath() + "]");
mBuffers.clear();
}
mLastBufferReceived = System.currentTimeMillis();
}
}
@Override
public Listener<RealBuffer> getFilteredRealBufferListener()
{
return this;
}
@Override
public void dispose()
{
stop();
}
@Override
public void reset()
{
}
/**
* Writes all audio currently in the queue to the file
* @throws IOException if there are any errors writing the audio
*/
private void write() throws IOException
{
RealBuffer buffer = mBuffers.poll();
while(buffer != null)
{
mWriter.write(ConversionUtils.convertToSigned16BitSamples(buffer));
buffer = mBuffers.poll();
}
}
public class BufferProcessor implements Runnable
{
public void run()
{
try
{
write();
}
catch(IOException ioe)
{
/* Stop this module if/when we get an IO exception */
mBuffers.clear();
stop();
mLog.error("IO Exception while trying to write to the wave writer", ioe);
}
}
}
/**
* This is used as a sentinel value to signal the buffer processor to end
*/
public class PoisonPill extends RealBuffer
{
public PoisonPill()
{
super( new float[ 1 ] );
}
}
}

View File

@@ -1,22 +1,25 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 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/>
* sdrtrunk
* Copyright (C) 2014-2017 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 record.wave;
import org.apache.commons.lang3.Validate;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
@@ -32,10 +35,7 @@ import javax.sound.sampled.AudioFormat;
public class WaveWriter implements AutoCloseable
{
// private final static Logger mLog = LoggerFactory.getLogger( WaveWriter.class );
private static final Pattern FILENAME_PATTERN =
Pattern.compile( "(.*_)(\\d+)(\\.wav)" );
private static final Pattern FILENAME_PATTERN = Pattern.compile( "(.*_)(\\d+)(\\.wav)" );
public static final long MAX_WAVE_SIZE = 2l * (long)Integer.MAX_VALUE;
private AudioFormat mAudioFormat;
@@ -56,11 +56,10 @@ public class WaveWriter implements AutoCloseable
* @param maxSize - maximum file size ( range: 1 - 4,294,967,294 bytes )
* @throws IOException - if there are any IO issues
*/
public WaveWriter( AudioFormat format, Path file, long maxSize )
throws IOException
public WaveWriter( AudioFormat format, Path file, long maxSize ) throws IOException
{
assert( format != null );
assert( file != null );
Validate.isTrue(format != null);
Validate.isTrue( file != null );
mAudioFormat = format;
mFile = file;
@@ -100,15 +99,11 @@ public class WaveWriter implements AutoCloseable
while( Files.exists( mFile ) )
{
mFile = Paths.get( mFile.toFile().getAbsolutePath()
.replace( ".wav", "_" + version + ".wav" ) );
mFile = Paths.get( mFile.toFile().getAbsolutePath().replace( ".wav", "_" + version + ".wav" ) );
version++;
}
Files.createFile( mFile );
mFileChannel = (FileChannel.open( mFile, StandardOpenOption.WRITE ) );
mFileChannel = (FileChannel.open( mFile, StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW ) );
ByteBuffer header = WaveUtils.getWaveHeader( mAudioFormat );
@@ -127,9 +122,18 @@ public class WaveWriter implements AutoCloseable
{
mFileChannel.force( true );
mFileChannel.close();
mFileChannel = null;
}
/**
@Override
protected void finalize() throws IOException
{
mFileChannel.force( true );
mFileChannel.close();
mFileChannel = null;
}
/**
* Writes the buffer contents to the file. Assumes that the buffer is full
* and the first byte of data is at position 0.
*/

View File

@@ -20,6 +20,7 @@ package sample.adapter;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import org.apache.commons.lang3.Validate;
import source.mixer.MixerChannel;
/**
@@ -34,7 +35,7 @@ public class ChannelShortAdapter implements ISampleAdapter
public ChannelShortAdapter( MixerChannel channel )
{
/* Only use with LEFT/RIGHT channels */
assert( channel != MixerChannel.MONO );
Validate.isTrue(channel != MixerChannel.MONO);
mMixerChannel = channel;
}

View File

@@ -17,6 +17,7 @@
******************************************************************************/
package sample.complex;
import org.apache.commons.lang3.Validate;
import sample.Listener;
/**
@@ -32,7 +33,7 @@ public class ComplexToComplexBufferAssembler implements ComplexSampleListener
public ComplexToComplexBufferAssembler( int bufferSize )
{
assert( bufferSize % 2 == 0 );
Validate.isTrue(bufferSize % 2 == 0);
mBufferSize = bufferSize;
mBuffer = new float[ mBufferSize ];

View File

@@ -113,7 +113,16 @@ public class FCD2TunerController extends FCDTunerController
FCD2TunerConfiguration fcd2 = (FCD2TunerConfiguration)config;
setFrequencyCorrection(fcd2.getFrequencyCorrection());
setFrequency(fcd2.getFrequency());
long frequency = MINIMUM_TUNABLE_FREQUENCY;
if(fcd2.getFrequency() >= MINIMUM_TUNABLE_FREQUENCY &&
fcd2.getFrequency() <= MAXIMUM_TUNABLE_FREQUENCY)
{
frequency = fcd2.getFrequency();
}
setFrequency(frequency);
setLNAGain(fcd2.getGainLNA());
setMixerGain(fcd2.getGainMixer());

File diff suppressed because it is too large Load Diff

View File

@@ -30,6 +30,7 @@ import java.util.Arrays;
import javax.swing.JPanel;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -282,7 +283,7 @@ public class SpectrumPanel extends JPanel
*/
public void setZoom( int zoom )
{
assert( 0 <= zoom && zoom <= 5 );
Validate.isTrue( 0 <= zoom && zoom <= 5 );
mZoom = zoom;
}
@@ -305,7 +306,7 @@ public class SpectrumPanel extends JPanel
*/
public void setSampleSize( double sampleSize )
{
assert( 2.0 <= sampleSize && sampleSize <= 32.0 );
Validate.isTrue(2.0 <= sampleSize && sampleSize <= 32.0);
mDBScale = (float)( 20.0 * Math.log10( Math.pow( 2.0, sampleSize - 1 ) ) );
}

View File

@@ -18,6 +18,8 @@
******************************************************************************/
package util;
import org.apache.commons.lang3.Validate;
import java.util.Arrays;
public class XTEA
@@ -58,7 +60,7 @@ public class XTEA
*/
public void setKey(byte[] key)
{
assert(key.length == 16);
Validate.isTrue(key.length == 16);
int keyInts[] = new int[8];
@@ -94,7 +96,7 @@ public class XTEA
*/
public byte[] encrypt(byte[] plainText)
{
assert(plainText.length == 8);
Validate.isTrue(plainText.length == 8);
//Convert the 8 bytes of plaintext to 2 integers
int result0 = (plainText[3] << 0) & MASK0 | (plainText[2] << 8) & MASK1 |