Merged master 8748

This commit is contained in:
Jordan Sherer
2018-08-05 11:33:30 -04:00
parent 8f8772f1bd
commit 62899069bf
1222 changed files with 70382 additions and 406763 deletions
@@ -1,233 +0,0 @@
set (LANGUAGES
en
)
set (common_SRCS
common/communication.adoc
common/license.adoc
common/links.adoc
)
set (UG_SRCS
docinfo.html
docinfo.xml
acknowledgements.adoc
astro_data.adoc
config-details.adoc
controls-functions-center.adoc
controls-functions-left.adoc
controls-functions-main-window.adoc
controls-functions-menus.adoc
controls-functions-messages.adoc
controls-functions-status-bar.adoc
controls-functions-wide-graph.adoc
cooperating-programs.adoc
faq.adoc
font-sizes.adoc
install-from-source.adoc
install-linux.adoc
install-mac.adoc
install-windows.adoc
introduction.adoc
protocols.adoc
logging.adoc
make-qso.adoc
new_features.adoc
odds_and_ends.adoc
platform-dependencies.adoc
protocols.adoc
settings-advanced.adoc
settings-audio.adoc
settings-colors.adoc
settings-frequencies.adoc
settings-general.adoc
settings-radio.adoc
settings-reporting.adoc
settings-txmacros.adoc
support.adoc
system-requirements.adoc
transceiver-setup.adoc
tutorial-example1.adoc
tutorial-example2.adoc
tutorial-example3.adoc
tutorial-main-window.adoc
tutorial-wide-graph-settings.adoc
utilities.adoc
vhf-features.adoc
wsjtx-main.adoc
wspr.adoc
)
set (UG_IMGS
images/130610_2343-wav-80.png
images/170709_135615.wav.png
images/AstroData_2.png
images/Astronomical_data.png
images/band-settings.png
images/colors.png
images/config-menu.png
images/decode-menu.png
images/decodes.png
images/download_samples.png
images/file-menu.png
images/freemsg.png
images/ft8_decodes.png
images/help-menu.png
images/JT4F.png
images/JT65B.png
images/MSK144.png
images/QRA64.png
images/WSPR_WideGraphControls.png
images/WSPR_1a.png
images/WSPR_2.png
images/jtalert.png
images/keyboard-shortcuts.png
images/log-qso.png
images/MacAppMenu.png
images/main-ui.png
images/main-ui-controls.png
images/misc-controls-center.png
images/misc-main-ui.png
images/mode-menu.png
images/new-msg-box.png
images/psk-reporter.png
images/r3666-config-screen-80.png
images/r3666-main-ui-80.png
images/r4148-txmac-ui.png
images/RadioTab.png
images/reporting.png
images/save-menu.png
images/settings-advanced.png
images/settings-audio.png
images/settings-frequencies.png
images/settings-general.png
images/setup-menu.png
images/special-mouse-commands.png
images/status-bar-a.png
images/traditional-msg-box.png
images/tx-macros.png
images/view-menu.png
images/wide-graph-controls.png
)
find_program (ASCIIDOCTOR_EXECUTABLE NAMES asciidoctor)
if (NOT ASCIIDOCTOR_EXECUTABLE)
message (FATAL_ERROR "asciidoctor is required to build the documentation
Building the documenation may optionally be turned off by setting the CMake
option WSJT_GENERATE_DOCS to OFF.")
endif (NOT ASCIIDOCTOR_EXECUTABLE)
find_program (FOPUB_EXECUTABLE NAMES fopub)
include (CMakeParseArguments)
# generate a document from asciidoc text files(s)
#
# HTML - generate an HTML document
# PDF - generate a PDF document
# SOURCE - top level asciidoc file
# ASCIIDOCTOR_OPTIONS - asciidoctor command options
# DEPENDS - dependent files
function (document)
cmake_parse_arguments (_args "HTML" "SOURCE;LANG;OUTPUT" "ASCIIDOCTOR_OPTIONS;PDF;DEPENDS" ${ARGN})
get_filename_component (_source_path ${_args_SOURCE} PATH)
get_filename_component (_source_name ${_args_SOURCE} NAME)
get_filename_component (_output_name_we ${_args_SOURCE} NAME_WE)
# HTML
if (${_args_HTML})
set (_html_file ${CMAKE_CURRENT_BINARY_DIR}/${_output_name_we}_${lang}.html)
add_custom_command (
OUTPUT ${_html_file}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${_source_path}/${lang}
COMMAND ${ASCIIDOCTOR_EXECUTABLE} ${_args_ASCIIDOCTOR_OPTIONS}
-b html5
-a VERSION_MAJOR=${WSJTX_VERSION_MAJOR}
-a VERSION_MINOR=${WSJTX_VERSION_MINOR}
-a VERSION_PATCH=${WSJTX_VERSION_PATCH}
-a VERSION=${wsjtx_VERSION}
--out-file=${_html_file} ${_source_name}
DEPENDS ${_args_DEPENDS}
COMMENT "Generating ${_html_file}"
)
list (APPEND _output_files ${_html_file})
endif (${_args_HTML})
# PDF
if (_args_PDF AND EXISTS ${FOPUB_EXECUTABLE})
set (_docbook_file ${CMAKE_CURRENT_BINARY_DIR}/${_output_name_we}_${lang}.xml)
set (_pdf_file_we ${CMAKE_CURRENT_BINARY_DIR}/${_output_name_we}_${lang})
if (${lang} MATCHES "^(en|es|fr)$") # en-us, fr-ca and es-{mx,co} use US-Letter or equivalent
set (_usl_commands
COMMAND ${FOPUB_EXECUTABLE} ARGS ${_docbook_file} ${_args_PDF} -param paper.type USLetter
COMMAND ${CMAKE_COMMAND} ARGS -E rename ${_pdf_file_we}.pdf '${_pdf_file_we} \(USLetter\).pdf'
)
list (APPEND _output_files "${_pdf_file_we} (USLetter).pdf")
endif ()
list (APPEND _output_files "${_pdf_file_we}.pdf")
add_custom_command (
OUTPUT ${_docbook_file} ${_output_files}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${_source_path}/${lang}
COMMAND ${ASCIIDOCTOR_EXECUTABLE} ARGS ${_args_ASCIIDOCTOR_OPTIONS}
-b docbook
-a data-uri!
-a VERSION_MAJOR=${WSJTX_VERSION_MAJOR}
-a VERSION_MINOR=${WSJTX_VERSION_MINOR}
-a VERSION_PATCH=${WSJTX_VERSION_PATCH}
-a VERSION=${wsjtx_VERSION}
-D ${CMAKE_CURRENT_BINARY_DIR}
-o ${_docbook_file} ${_source_name}
${_usl_commands}
COMMAND ${FOPUB_EXECUTABLE} ARGS ${_docbook_file} ${_args_PDF} -param paper.type A4
COMMAND ${CMAKE_COMMAND} ARGS -E rename ${_pdf_file_we}.pdf '${_pdf_file_we}.pdf'
DEPENDS ${_args_DEPENDS}
COMMENT "Generating ${_output_files}"
)
endif (_args_PDF AND EXISTS ${FOPUB_EXECUTABLE})
set (${_args_OUTPUT} ${_output_files} PARENT_SCOPE)
endfunction (document)
set (htmls)
set (pdfs)
foreach (lang ${LANGUAGES})
set (_sources)
foreach (_src ${UG_SRCS} ${UG_IMGS})
list (APPEND _sources "user_guide/${lang}/${_src}")
endforeach ()
document(
HTML
SOURCE user_guide/wsjtx-main.adoc
LANG "${lang}"
OUTPUT html
ASCIIDOCTOR_OPTIONS -d book -a data-uri -a toc=left -a max-width=1024px
DEPENDS ${common_SRCS} ${_sources}
)
document(
PDF -param body.font.master 11 -param body.font.family "'Noto Sans, Helvetica, sans-serif'" -param title.font.family "'Noto Serif, Times New Roman, serif'" -param page.margin.inner 1cm -param page.margin.outer 1cm -param page.margin.top 0.75cm -param page.margin.bottom 0.5cm -param generate.toc 0
SOURCE user_guide/wsjtx-main.adoc
LANG "${lang}"
OUTPUT pdf
ASCIIDOCTOR_OPTIONS -d book
DEPENDS ${common_SRCS} ${_sources}
)
list (APPEND htmls "${html}")
list (APPEND pdfs "${pdf}")
endforeach ()
add_custom_target (docs ALL DEPENDS ${htmls} ${pdfs})
foreach (_html ${htmls})
get_filename_component (_path ${_html} PATH)
get_filename_component (_nwe ${_html} NAME_WE)
get_filename_component (_ext ${_html} EXT)
string (REGEX REPLACE "_en$" "" _nwe ${_nwe})
install (FILES
${_html}
DESTINATION ${CMAKE_INSTALL_DOCDIR}
RENAME ${_nwe}-${wsjtx_VERSION}${_ext}
#COMPONENT runtime
)
endforeach ()
@@ -1,98 +0,0 @@
#ifndef MESSAGE_CLIENT_HPP__
#define MESSAGE_CLIENT_HPP__
#include <QObject>
#include <QTime>
#include <QDateTime>
#include <QString>
#include "Radio.hpp"
#include "pimpl_h.hpp"
class QByteArray;
class QHostAddress;
//
// MessageClient - Manage messages sent and replies received from a
// matching server (MessageServer) at the other end of
// the wire
//
//
// Each outgoing message type is a Qt slot
//
class MessageClient
: public QObject
{
Q_OBJECT;
public:
using Frequency = Radio::Frequency;
using port_type = quint16;
// instantiate and initiate a host lookup on the server
//
// messages will be silently dropped until a server host lookup is complete
MessageClient (QString const& id, QString const& version, QString const& revision,
QString const& server, port_type server_port, QObject * parent = nullptr);
// query server details
QHostAddress server_address () const;
port_type server_port () const;
// initiate a new server host lookup or is the server name is empty
// the sending of messages is disabled
Q_SLOT void set_server (QString const& server = QString {});
// change the server port messages are sent to
Q_SLOT void set_server_port (port_type server_port = 0u);
// outgoing messages
Q_SLOT void status_update (Frequency, QString const& mode, QString const& dx_call, QString const& report
, QString const& tx_mode, bool tx_enabled, bool transmitting, bool decoding
, qint32 rx_df, qint32 tx_df, QString const& de_call, QString const& de_grid
, QString const& dx_grid, bool watchdog_timeout, QString const& sub_mode
, bool fast_mode);
Q_SLOT void decode (bool is_new, QTime time, qint32 snr, float delta_time, quint32 delta_frequency
, QString const& mode, QString const& message, bool low_confidence
, bool off_air);
Q_SLOT void WSPR_decode (bool is_new, QTime time, qint32 snr, float delta_time, Frequency
, qint32 drift, QString const& callsign, QString const& grid, qint32 power
, bool off_air);
Q_SLOT void clear_decodes ();
Q_SLOT void qso_logged (QDateTime time_off, QString const& dx_call, QString const& dx_grid
, Frequency dial_frequency, QString const& mode, QString const& report_sent
, QString const& report_received, QString const& tx_power, QString const& comments
, QString const& name, QDateTime time_on);
// this slot may be used to send arbitrary UDP datagrams to and
// destination allowing the underlying socket to be used for general
// UDP messaging if desired
Q_SLOT void send_raw_datagram (QByteArray const&, QHostAddress const& dest_address, port_type dest_port);
// this signal is emitted if the server sends us a reply, the only
// reply supported is reply to a prior CQ or QRZ message
Q_SIGNAL void reply (QTime, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode
, QString const& message_text, bool low_confidence, quint8 modifiers);
// this signal is emitted if the server has requested a replay of
// all decodes
Q_SIGNAL void replay ();
// this signal is emitted if the server has requested immediate (or
// auto Tx if auto_only is true) transmission to halt
Q_SIGNAL void halt_tx (bool auto_only);
// this signal is emitted if the server has requested a new free
// message text
Q_SIGNAL void free_text (QString const&, bool send);
// this signal is emitted when network errors occur or if a host
// lookup fails
Q_SIGNAL void error (QString const&) const;
private:
class impl;
pimpl<impl> m_;
};
#endif
@@ -1,87 +0,0 @@
<HTML><HEAD>
<TITLE> Examples of LDPC Program Usage </TITLE>
</HEAD><BODY>
<H1> Examples of LDPC Program Usage </H1>
<P>Below, are some command files containing examples of the use of
the <A HREF="progs.html">LDPC programs</A>, together with the output I
obtained for these examples. Output on other machines might
conceivably be slightly different, due to different round-off errors.
The <A HREF="run-examples"><TT>run-examples</TT></A> script runs all the example
scripts and compares their output with the outputs that I obtained (on
a Pentium machine).
<P><A HREF="ex-ham7b">ex-ham7b</A>,
output in <A HREF="ex-ham7b-out">ex-ham7b-out</A>
<BLOCKQUOTE>
A (7,4) Hamming code used with a BSC.
Demonstrates encoding of random messages and decoding to minimize
bit error rate by exhaustive enumeration.
</BLOCKQUOTE>
<P><A HREF="ex-ham7a">ex-ham7a</A>,
output in <A HREF="ex-ham7a-out">ex-ham7a-out</A>
<BLOCKQUOTE>
A (7,4) Hamming code used with an AWGN channel. Tested using zero messages.
Decoded by exhaustive enumeration to minimize either block or bit error rate,
and by probability propagation.
</BLOCKQUOTE>
<P><A HREF="ex-dep">ex-dep</A>,
output in <A HREF="ex-dep-out">ex-dep-out</A>
<BLOCKQUOTE>
Examples of how parity check matrices with linearly dependent rows (ie,
redundant parity checks) are handled. This is probably not of
great interest to most users.
</BLOCKQUOTE>
<P><A HREF="ex-ldpc-encode">ex-ldpc-encode</A>,
output in <A HREF="ex-ldpc-encode-out">ex-ldpc-encode-out</A>
<BLOCKQUOTE>
Encodes messages with an LDPC code using sparse, dense, and mixed
representations of the generator matrix.
</BLOCKQUOTE>
<P><A HREF="ex-ldpc36-1000a">ex-ldpc36-1000a</A>,
output in <A HREF="ex-ldpc36-1000a-out">ex-ldpc36-1000a-out</A>
<BLOCKQUOTE>
A (2000,1000) LDPC code with 3 checks per bit and 6 bits per check.
Three encoding methods are tried out, and the code is
tested on an AWGN channel at various noise levels, using random messages.
</BLOCKQUOTE>
<P><A HREF="ex-ldpc36-5000a">ex-ldpc36-5000a</A>,
output in <A HREF="ex-ldpc36-5000a-out">ex-ldpc36-5000a-out</A>
<BLOCKQUOTE>
A (10000,5000) LDPC code with 3 checks per bit and 6 bits per check.
Tested on an AWGN channel at various noise levels, using random messages.
Pipes are used to avoid creating lots of files.
</BLOCKQUOTE>
<P><A HREF="ex-ldpcvar-5000a">ex-ldpcvar-5000a</A>,
output in <A HREF="ex-ldpcvar-5000a-out">ex-ldpcvar-5000a-out</A>
<BLOCKQUOTE>
A (10000,5000) LDPC code with the number of checks per bit varying from 2 to 7.
Tested on an AWGN channel at various noise levels, using random messages.
Pipes are used to avoid creating lots of files. Performance is better than
for the code above in which the number of checks is the same for all bits.
</BLOCKQUOTE>
<P><A HREF="ex-wrong-model">ex-wrong-model</A>,
output in <A HREF="ex-wrong-model-out">ex-wrong-model-out</A>
<BLOCKQUOTE>
Tests what happens when messages are decoded using the wrong noise
model, including using the right type of model but with the wrong
noise level, and using the wrong type of model (ie, using an AWLN model
for messages transmitted through an AWGN channel, or vice versa).
</BLOCKQUOTE>
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>
@@ -0,0 +1,78 @@
module jt65_test
! Test the JT65 decoder for WSJT-X
implicit none
public :: test
integer, parameter, public :: NZMAX=60*12000
integer, public :: nft
contains
subroutine test (dd,nutc,nflow,nfhigh,nfqso,ntol,nsubmode,n2pass,nrobust &
,ntrials,naggressive,ndepth,mycall,hiscall,hisgrid,nexp_decode, &
nQSOProgress,ljt65apon)
use timer_module, only: timer
use jt65_decode
implicit none
include 'constants.f90'
real, intent(in) :: dd(NZMAX)
integer, intent(in) :: nutc, nflow, nfhigh, nfqso, ntol, nsubmode, n2pass &
, ntrials, naggressive, ndepth, nexp_decode, nQSOProgress
logical, intent(in) :: nrobust,ljt65apon
character(len=12), intent(in) :: mycall, hiscall
character(len=6), intent(in) :: hisgrid
type(jt65_decoder) :: my_decoder
logical nclearave !### Should be a dummy arg?
nclearave=.false.
call timer('jt65a ',0)
call my_decoder%decode(my_callback,dd,npts=52*12000,newdat=.true., &
nutc=nutc,nf1=nflow,nf2=nfhigh,nfqso=nfqso,ntol=ntol, &
nsubmode=nsubmode, minsync=-1,nagain=.false.,n2pass=n2pass, &
nrobust=nrobust,ntrials=ntrials,naggressive=naggressive, &
ndepth=ndepth,emedelay=0.0,clearave=nclearave,mycall=mycall, &
hiscall=hiscall,hisgrid=hisgrid,nexp_decode=nexp_decode, &
nQSOProgress=nQSOProgress,ljt65apon=ljt65apon)
call timer('jt65a ',1)
end subroutine test
subroutine my_callback (this,sync,snr,dt,freq,drift,nflip,width, &
decoded,ft,qual,smo,sum,minsync)
use jt65_decode
implicit none
class(jt65_decoder), intent(inout) :: this
real, intent(in) :: sync
integer, intent(in) :: snr
real, intent(in) :: dt
integer, intent(in) :: freq
integer, intent(in) :: drift
integer, intent(in) :: nflip
real, intent(in) :: width
character(len=22), intent(in) :: decoded
integer, intent(in) :: ft
integer, intent(in) :: qual
integer, intent(in) :: smo
integer, intent(in) :: sum
integer, intent(in) :: minsync
integer nwidth
real t
if(minsync+nflip+qual.eq.-9999) stop !Silence compiler warning
t=max(0.0,width*width-7.2)
nwidth=max(nint(sqrt(t)),2)
!### deal with nflip here! ###
!### also single_decode, csync, etc... ###
write(*,1012) nint(sync),snr,dt,freq,drift,nwidth, &
decoded,ft,sum,smo
1012 format(i4,i5,f6.2,i5,i4,i3,1x,a22,' JT65',3i3)
nft=ft
call flush(6)
end subroutine my_callback
end module jt65_test
@@ -1,329 +0,0 @@
#include "Modulator.hpp"
#include <limits>
#include <qmath.h>
#include <QDateTime>
#include <QDebug>
#include "mainwindow.h"
#include "soundout.h"
#include "moc_Modulator.cpp"
extern float gran(); // Noise generator (for tests only)
#define RAMP_INCREMENT 64 // MUST be an integral factor of 2^16
#if defined (WSJT_SOFT_KEYING)
# define SOFT_KEYING WSJT_SOFT_KEYING
#else
# define SOFT_KEYING 1
#endif
double constexpr Modulator::m_twoPi;
// float wpm=20.0;
// unsigned m_nspd=1.2*48000.0/wpm;
// m_nspd=3072; //18.75 WPM
Modulator::Modulator (unsigned frameRate, unsigned periodLengthInSeconds,
QObject * parent)
: AudioDevice {parent}
, m_quickClose {false}
, m_phi {0.0}
, m_toneSpacing {0.0}
, m_fSpread {0.0}
, m_frameRate {frameRate}
, m_period {periodLengthInSeconds}
, m_state {Idle}
, m_tuning {false}
, m_cwLevel {false}
, m_j0 {-1}
, m_toneFrequency0 {1500.0}
{
}
void Modulator::start (unsigned symbolsLength, double framesPerSymbol,
double frequency, double toneSpacing,
SoundOutput * stream, Channel channel,
bool synchronize, bool fastMode, double dBSNR, int TRperiod)
{
Q_ASSERT (stream);
// Time according to this computer which becomes our base time
qint64 ms0 = QDateTime::currentMSecsSinceEpoch() % 86400000;
if (m_state != Idle)
{
stop ();
}
m_quickClose = false;
m_symbolsLength = symbolsLength;
m_isym0 = std::numeric_limits<unsigned>::max (); // big number
m_frequency0 = 0.;
m_phi = 0.;
m_addNoise = dBSNR < 0.;
m_nsps = framesPerSymbol;
m_frequency = frequency;
m_amp = std::numeric_limits<qint16>::max ();
m_toneSpacing = toneSpacing;
m_bFastMode=fastMode;
m_TRperiod=TRperiod;
unsigned delay_ms = 1920 == m_nsps && 15 == m_period ? 500 : 1000;
// noise generator parameters
if (m_addNoise) {
m_snr = qPow (10.0, 0.05 * (dBSNR - 6.0));
m_fac = 3000.0;
if (m_snr > 1.0) m_fac = 3000.0 / m_snr;
}
unsigned mstr = ms0 % (1000 * m_period); // ms in period
// round up to an exact portion of a second that allows for startup
// delays
m_ic = (mstr / delay_ms) * m_frameRate * delay_ms / 1000;
if(m_bFastMode) m_ic=0;
m_silentFrames = 0;
// calculate number of silent frames to send
if (synchronize && !m_tuning && !m_bFastMode) {
m_silentFrames = m_ic + m_frameRate / (1000 / delay_ms) - (mstr * (m_frameRate / 1000));
}
initialize (QIODevice::ReadOnly, channel);
Q_EMIT stateChanged ((m_state = (synchronize && m_silentFrames) ?
Synchronizing : Active));
m_stream = stream;
if (m_stream) m_stream->restart (this);
}
void Modulator::tune (bool newState)
{
m_tuning = newState;
if (!m_tuning) stop (true);
}
void Modulator::stop (bool quick)
{
m_quickClose = quick;
close ();
}
void Modulator::close ()
{
if (m_stream)
{
if (m_quickClose)
{
m_stream->reset ();
}
else
{
m_stream->stop ();
}
}
if (m_state != Idle)
{
Q_EMIT stateChanged ((m_state = Idle));
}
AudioDevice::close ();
}
qint64 Modulator::readData (char * data, qint64 maxSize)
{
double toneFrequency=1500.0;
if(m_nsps==6) {
toneFrequency=1000.0;
m_frequency=1000.0;
m_frequency0=1000.0;
}
if(maxSize==0) return 0;
Q_ASSERT (!(maxSize % qint64 (bytesPerFrame ()))); // no torn frames
Q_ASSERT (isOpen ());
qint64 numFrames (maxSize / bytesPerFrame ());
qint16 * samples (reinterpret_cast<qint16 *> (data));
qint16 * end (samples + numFrames * (bytesPerFrame () / sizeof (qint16)));
qint64 framesGenerated (0);
switch (m_state)
{
case Synchronizing:
{
if (m_silentFrames) { // send silence up to first second
framesGenerated = qMin (m_silentFrames, numFrames);
for ( ; samples != end; samples = load (0, samples)) { // silence
}
m_silentFrames -= framesGenerated;
return framesGenerated * bytesPerFrame ();
}
Q_EMIT stateChanged ((m_state = Active));
m_cwLevel = false;
m_ramp = 0; // prepare for CW wave shaping
}
// fall through
case Active:
{
unsigned int isym=0;
if(!m_tuning) isym=m_ic/(4.0*m_nsps); // Actual fsample=48000
bool slowCwId=((isym >= m_symbolsLength) && (icw[0] > 0)) && (!m_bFastMode);
if(m_TRperiod==3) slowCwId=false;
bool fastCwId=false;
static bool bCwId=false;
qint64 ms = QDateTime::currentMSecsSinceEpoch();
float tsec=0.001*(ms % (1000*m_TRperiod));
if(m_bFastMode and (icw[0]>0) and (tsec>(m_TRperiod-5.0))) fastCwId=true;
if(!m_bFastMode) m_nspd=2560; // 22.5 WPM
if(slowCwId or fastCwId) { // Transmit CW ID?
m_dphi = m_twoPi*m_frequency/m_frameRate;
if(m_bFastMode and !bCwId) {
m_frequency=1500; // Set params for CW ID
m_dphi = m_twoPi*m_frequency/m_frameRate;
m_symbolsLength=126;
m_nsps=4096.0*12000.0/11025.0;
m_ic=2246949;
m_nspd=2560; // 22.5 WPM
if(icw[0]*m_nspd/48000.0 > 4.0) m_nspd=4.0*48000.0/icw[0]; //Faster CW for long calls
}
bCwId=true;
unsigned ic0 = m_symbolsLength * 4 * m_nsps;
unsigned j(0);
while (samples != end) {
j = (m_ic - ic0)/m_nspd + 1; // symbol of this sample
bool level {bool (icw[j])};
m_phi += m_dphi;
if (m_phi > m_twoPi) m_phi -= m_twoPi;
qint16 sample=0;
float amp=32767.0;
float x=0;
if(m_ramp!=0) {
x=qSin(float(m_phi));
if(SOFT_KEYING) {
amp=qAbs(qint32(m_ramp));
if(amp>32767.0) amp=32767.0;
}
sample=round(amp*x);
}
if(m_bFastMode) {
sample=0;
if(level) sample=32767.0*x;
}
if (int (j) <= icw[0] && j < NUM_CW_SYMBOLS) { // stop condition
samples = load (postProcessSample (sample), samples);
++framesGenerated;
++m_ic;
} else {
Q_EMIT stateChanged ((m_state = Idle));
return framesGenerated * bytesPerFrame ();
}
// adjust ramp
if ((m_ramp != 0 && m_ramp != std::numeric_limits<qint16>::min ()) || level != m_cwLevel) {
// either ramp has terminated at max/min or direction has changed
m_ramp += RAMP_INCREMENT; // ramp
}
m_cwLevel = level;
}
return framesGenerated * bytesPerFrame ();
} else {
bCwId=false;
} //End of code for CW ID
double const baud (12000.0 / m_nsps);
// fade out parameters (no fade out for tuning)
unsigned int i0,i1;
if(m_tuning) {
i1 = i0 = (m_bFastMode ? 999999 : 9999) * m_nsps;
} else {
i0=(m_symbolsLength - 0.017) * 4.0 * m_nsps;
i1= m_symbolsLength * 4.0 * m_nsps;
}
if(m_bFastMode and !m_tuning) {
i1=m_TRperiod*48000 - 24000;
i0=i1-816;
}
for (unsigned i = 0; i < numFrames && m_ic <= i1; ++i) {
isym=0;
if(!m_tuning and m_TRperiod!=3) isym=m_ic / (4.0 * m_nsps); //Actual
//fsample=48000
if(m_bFastMode) isym=isym%m_symbolsLength;
if (isym != m_isym0 || m_frequency != m_frequency0) {
if(itone[0]>=100) {
m_toneFrequency0=itone[0];
} else {
if(m_toneSpacing==0.0) {
m_toneFrequency0=m_frequency + itone[isym]*baud;
} else {
m_toneFrequency0=m_frequency + itone[isym]*m_toneSpacing;
}
}
// qDebug() << "B" << m_bFastMode << m_ic << numFrames << isym << itone[isym]
// << m_toneFrequency0 << m_nsps;
m_dphi = m_twoPi * m_toneFrequency0 / m_frameRate;
m_isym0 = isym;
m_frequency0 = m_frequency; //???
}
int j=m_ic/480;
if(m_fSpread>0.0 and j!=m_j0) {
float x1=(float)qrand()/RAND_MAX;
float x2=(float)qrand()/RAND_MAX;
toneFrequency = m_toneFrequency0 + 0.5*m_fSpread*(x1+x2-1.0);
m_dphi = m_twoPi * toneFrequency / m_frameRate;
m_j0=j;
}
m_phi += m_dphi;
if (m_phi > m_twoPi) m_phi -= m_twoPi;
if (m_ic > i0) m_amp = 0.98 * m_amp;
if (m_ic > i1) m_amp = 0.0;
samples = load (postProcessSample (m_amp * qSin (m_phi)), samples);
++framesGenerated;
++m_ic;
}
if (m_amp == 0.0) { // TODO G4WJS: compare double with zero might not be wise
if (icw[0] == 0) {
// no CW ID to send
Q_EMIT stateChanged ((m_state = Idle));
return framesGenerated * bytesPerFrame ();
}
m_phi = 0.0;
}
m_frequency0 = m_frequency;
// done for this chunk - continue on next call
return framesGenerated * bytesPerFrame ();
}
// fall through
case Idle:
break;
}
Q_ASSERT (Idle == m_state);
return 0;
}
qint16 Modulator::postProcessSample (qint16 sample) const
{
if (m_addNoise) { // Test frame, we'll add noise
qint32 s = m_fac * (gran () + sample * m_snr / 32768.0);
if (s > std::numeric_limits<qint16>::max ()) {
s = std::numeric_limits<qint16>::max ();
}
if (s < std::numeric_limits<qint16>::min ()) {
s = std::numeric_limits<qint16>::min ();
}
sample = s;
}
return sample;
}
File diff suppressed because it is too large Load Diff