mirror of
https://github.com/dj0abr/SSB_HighSpeed_Modem.git
synced 2026-08-26 13:55:41 -04:00
update
This commit is contained in:
+1
-1
@@ -9,7 +9,7 @@
|
||||
|
||||
CXXFLAGS = -Wall -O3 -std=c++0x -Wno-write-strings -Wno-narrowing
|
||||
LDFLAGS = -lpthread -lrt -lsndfile -lasound -lm -lopus -lfftw3 -lfftw3_threads -lliquid -lcodec2 -lsoundio
|
||||
OBJ = hsmodem.o constellation.o crc16.o frame_packer.o main_helper.o scrambler.o speed.o fec.o udp.o fft.o liquid_if.o symboltracker.o voiceprocessor.o codec2.o soundio.o fifo.o announcement.o fifo_voice.o voiceio.o tuning.o
|
||||
OBJ = hsmodem.o constellation.o crc16.o frame_packer.o main_helper.o scrambler.o speed.o fec.o udp.o fft.o liquid_if.o symboltracker.o voiceprocessor.o codec2.o soundio.o fifo.o announcement.o fifo_voice.o voiceio.o tuning.o rtty.o
|
||||
|
||||
default: $(OBJ)
|
||||
mkdir -p ../hsmodemLinux
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,32 +0,0 @@
|
||||
e:\funk\hsmodem\hsmodem\release\vc140.pdb
|
||||
e:\funk\hsmodem\hsmodem\release\tuning.obj
|
||||
e:\funk\hsmodem\hsmodem\release\liquid_if.obj
|
||||
e:\funk\hsmodem\hsmodem\release\fft.obj
|
||||
e:\funk\hsmodem\hsmodem\release\voiceprocessor.obj
|
||||
e:\funk\hsmodem\hsmodem\release\voiceio.obj
|
||||
e:\funk\hsmodem\hsmodem\release\udp.obj
|
||||
e:\funk\hsmodem\hsmodem\release\symboltracker.obj
|
||||
e:\funk\hsmodem\hsmodem\release\speed.obj
|
||||
e:\funk\hsmodem\hsmodem\release\soundio.obj
|
||||
e:\funk\hsmodem\hsmodem\release\scrambler.obj
|
||||
e:\funk\hsmodem\hsmodem\release\main_helper.obj
|
||||
e:\funk\hsmodem\hsmodem\release\hsmodem.obj
|
||||
e:\funk\hsmodem\hsmodem\release\frame_packer.obj
|
||||
e:\funk\hsmodem\hsmodem\release\fifo_voice.obj
|
||||
e:\funk\hsmodem\hsmodem\release\fifo.obj
|
||||
e:\funk\hsmodem\hsmodem\release\fec.obj
|
||||
e:\funk\hsmodem\hsmodem\release\crc16.obj
|
||||
e:\funk\hsmodem\hsmodem\release\constellation.obj
|
||||
e:\funk\hsmodem\hsmodem\release\codec2.obj
|
||||
e:\funk\hsmodem\hsmodem\release\announcement.obj
|
||||
e:\funk\hsmodem\winrelease\hsmodem.exe
|
||||
e:\funk\hsmodem\winrelease\hsmodem.ipdb
|
||||
e:\funk\hsmodem\winrelease\hsmodem.iobj
|
||||
e:\funk\hsmodem\winrelease\hsmodem.pdb
|
||||
e:\funk\hsmodem\hsmodem\..\winrelease\hsmodem.exe
|
||||
e:\funk\hsmodem\hsmodem\release\hsmodem.tlog\cl.command.1.tlog
|
||||
e:\funk\hsmodem\hsmodem\release\hsmodem.tlog\cl.read.1.tlog
|
||||
e:\funk\hsmodem\hsmodem\release\hsmodem.tlog\cl.write.1.tlog
|
||||
e:\funk\hsmodem\hsmodem\release\hsmodem.tlog\link.command.1.tlog
|
||||
e:\funk\hsmodem\hsmodem\release\hsmodem.tlog\link.read.1.tlog
|
||||
e:\funk\hsmodem\hsmodem\release\hsmodem.tlog\link.write.1.tlog
|
||||
@@ -1,24 +0,0 @@
|
||||
announcement.cpp
|
||||
codec2.cpp
|
||||
constellation.cpp
|
||||
crc16.cpp
|
||||
fec.cpp
|
||||
fft.cpp
|
||||
fifo.cpp
|
||||
fifo_voice.cpp
|
||||
frame_packer.cpp
|
||||
hsmodem.cpp
|
||||
liquid_if.cpp
|
||||
main_helper.cpp
|
||||
scrambler.cpp
|
||||
soundio.cpp
|
||||
speed.cpp
|
||||
symboltracker.cpp
|
||||
tuning.cpp
|
||||
udp.cpp
|
||||
voiceio.cpp
|
||||
voiceprocessor.cpp
|
||||
Code wird generiert.
|
||||
All 602 functions were compiled because no usable IPDB/IOBJ from previous compilation was found.
|
||||
Codegenerierung ist abgeschlossen.
|
||||
hsmodem.vcxproj -> E:\funk\hsmodem\hsmodem\..\WinRelease\hsmodem.exe
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,2 +0,0 @@
|
||||
#TargetFrameworkVersion=v4.0:PlatformToolSet=v140_xp:EnableManagedIncrementalBuild=false:VCToolArchitecture=Native32Bit:WindowsTargetPlatformVersion=8.1
|
||||
Release|Win32|E:\funk\hsmodem\|
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+6
-9
@@ -153,8 +153,8 @@ uint16_t *make_waterfall(float fre, int *retlen)
|
||||
}
|
||||
|
||||
// smooth fft output
|
||||
const int smoothX = 6; // must be an even number !
|
||||
const int smoothY = 3;
|
||||
const int smoothX = 2; // must be an even number !
|
||||
const int smoothY = 10;
|
||||
int yidx = 0;
|
||||
|
||||
uint16_t* mean(uint16_t* f)
|
||||
@@ -164,7 +164,7 @@ uint16_t* mean(uint16_t* f)
|
||||
|
||||
if (tuning)
|
||||
return f;
|
||||
|
||||
|
||||
// first smooth X values
|
||||
for (int x = 0; x < smoothX / 2; x++)
|
||||
fa[x] = f[x];
|
||||
@@ -179,8 +179,9 @@ uint16_t* mean(uint16_t* f)
|
||||
|
||||
for (int x = fftcount - smoothX / 2; x < fftcount; x++)
|
||||
fa[x] = f[x];
|
||||
|
||||
|
||||
// smooth Y values
|
||||
|
||||
static uint16_t yarr[smoothY][FFT_AUDIOSAMPLERATE / 2 + 1];
|
||||
for (int i = 0; i < fftcount; i++)
|
||||
yarr[yidx][i] = fa[i];
|
||||
@@ -194,10 +195,6 @@ uint16_t* mean(uint16_t* f)
|
||||
fa[i] /= smoothY;
|
||||
}
|
||||
|
||||
// do not smooth 2950 to 3050 Hz
|
||||
for (int i = 295; i < 305; i++)
|
||||
fa[i] = f[i];
|
||||
|
||||
return fa;
|
||||
}
|
||||
|
||||
@@ -216,7 +213,7 @@ void _init_fft()
|
||||
// decimate 44.1k or 48k down to 8000Hz
|
||||
// the FFT rate is 800, but we feed it with 8000 Samplerate
|
||||
// this results in a new fft every 100ms with a resolution of 10 Hz
|
||||
float ratio = 10.0f * (float)FFT_AUDIOSAMPLERATE / (float)physcaprate;
|
||||
float ratio = 10.0f * (float)FFT_AUDIOSAMPLERATE / (float)physRXcaprate;
|
||||
fftdecim = msresamp_crcf_create(ratio, 40.0f);
|
||||
|
||||
}
|
||||
|
||||
+17
-6
@@ -68,7 +68,7 @@ int trigger_resetmodem = 0;
|
||||
char homepath[1000] = { 0 };
|
||||
|
||||
int caprate = 44100;
|
||||
int physcaprate = 44100;
|
||||
int physRXcaprate = 44100;
|
||||
int txinterpolfactor = 20;
|
||||
int rxPreInterpolfactor = 5;
|
||||
int linespeed = 4410;
|
||||
@@ -87,7 +87,7 @@ int announcement = 0;
|
||||
int VoiceAudioMode = VOICEMODE_OFF;
|
||||
int codec = 1; // 0=opus, 1=codec2
|
||||
int tuning = 0;
|
||||
int marker = 0;
|
||||
int marker = 1;
|
||||
|
||||
int init_audio_result = 0;
|
||||
int init_voice_result = 0;
|
||||
@@ -382,6 +382,8 @@ void bc_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
|
||||
char rxip[20];
|
||||
strcpy(rxip, inet_ntoa(rxsock->sin_addr));
|
||||
|
||||
//printf("GUI search received:%s\n",rxip);
|
||||
|
||||
if (fixappIP == 0)
|
||||
{
|
||||
if (strcmp(appIP, rxip))
|
||||
@@ -391,13 +393,14 @@ void bc_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
|
||||
// there was an appIP already
|
||||
// before accepting this new one, wait 3 seconds
|
||||
int ts = (int)(actms - lastms);
|
||||
printf("new app IP: %s since %d, restarting modems\n", rxip,ts);
|
||||
//printf("new app IP: %s since %d, restarting modems\n", rxip,ts);
|
||||
if (ts < 3000)
|
||||
return;
|
||||
}
|
||||
printf("first app IP: %s, restarting modems\n", rxip);
|
||||
//printf("first app IP: %s, restarting modems\n", rxip);
|
||||
restart_modems = 1;
|
||||
}
|
||||
|
||||
strcpy(appIP, rxip);
|
||||
//printf("app (%s) is searching modem. Sending modem IP to the app\n",appIP);
|
||||
// App searches for the modem IP, mirror the received messages
|
||||
@@ -569,8 +572,7 @@ void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
|
||||
if (type == 27)
|
||||
{
|
||||
// send Tuning tones
|
||||
printf("Tuning mode active\n");
|
||||
VoiceAudioMode = VOICEMODE_OFF;
|
||||
printf("Tuning mode active:%d\n",minfo);
|
||||
tuning_runtime = 0;
|
||||
tuning = minfo;
|
||||
return;
|
||||
@@ -583,6 +585,15 @@ void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == 29)
|
||||
{
|
||||
int v = minfo;
|
||||
if (v > 128)
|
||||
v = v - 255;
|
||||
modifyRXfreq(float(v));
|
||||
return;
|
||||
}
|
||||
|
||||
// here we are with payload data to be sent via the modulator
|
||||
|
||||
if (len != (PAYLOADLEN + 2))
|
||||
|
||||
+5
-1
@@ -206,6 +206,10 @@ void io_clear_voice_fifos();
|
||||
float do_tuning(int send);
|
||||
void init_tune();
|
||||
float singleFrequency();
|
||||
void rtty_tx();
|
||||
int rtty_rx();
|
||||
void modifyRXfreq(float fr);
|
||||
void showbytestring16(char* title, uint16_t* data, int anz);
|
||||
|
||||
|
||||
extern int speedmode;
|
||||
@@ -240,7 +244,7 @@ extern int rxlevel_deteced;
|
||||
extern int rx_in_sync;
|
||||
extern float softwareMICvolume;
|
||||
extern float softwareLSvolume;
|
||||
extern int physcaprate;
|
||||
extern int physRXcaprate;
|
||||
extern int restart_modems;
|
||||
extern int safemode;
|
||||
extern char homepath[];
|
||||
|
||||
@@ -251,6 +251,7 @@
|
||||
<ClCompile Include="hsmodem.cpp" />
|
||||
<ClCompile Include="liquid_if.cpp" />
|
||||
<ClCompile Include="main_helper.cpp" />
|
||||
<ClCompile Include="rtty.cpp" />
|
||||
<ClCompile Include="scrambler.cpp" />
|
||||
<ClCompile Include="soundio.cpp" />
|
||||
<ClCompile Include="speed.cpp" />
|
||||
|
||||
@@ -75,6 +75,9 @@
|
||||
<ClCompile Include="tuning.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="rtty.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="hsmodem.h">
|
||||
|
||||
+84
-8
@@ -209,7 +209,7 @@ void modulator(uint8_t sym_in)
|
||||
}
|
||||
|
||||
if(marker)
|
||||
usb += singleFrequency() / 10.0f;
|
||||
usb += singleFrequency() / 4.0f;
|
||||
|
||||
io_pb_write_fifo(usb * 0.2f); // reduce volume and send to soundcard
|
||||
}
|
||||
@@ -221,6 +221,7 @@ nco_crcf dnnco = NULL;
|
||||
symtrack_cccf symtrack = NULL;
|
||||
firdecim_crcf decim = NULL;
|
||||
msresamp_crcf adecim = NULL;
|
||||
msresamp_crcf lsresamp = NULL;
|
||||
|
||||
// decimator parameters
|
||||
unsigned int m_predec = 8; // filter delay
|
||||
@@ -240,16 +241,27 @@ float bandwidth_st = 0.9f; // loop filter bandwidth
|
||||
uint8_t maxLevel = 0; // maximum RXlevel over the last x samples in %
|
||||
uint8_t maxTXLevel = 0; // maximum TXlevel over the last x samples in %
|
||||
|
||||
float radians_per_sample = ((2.0f * (float)M_PI * (float)FREQUENCY) / (float)caprate);
|
||||
float last_radians_per_sample = 0;
|
||||
float actfrequency = (float)FREQUENCY;
|
||||
|
||||
void modifyRXfreq(float diff_Hz)
|
||||
{
|
||||
actfrequency += diff_Hz;
|
||||
printf("set:%f Hz\n", actfrequency);
|
||||
radians_per_sample = ((2.0f * (float)M_PI * actfrequency) / (float)caprate);
|
||||
}
|
||||
|
||||
void init_demodulator()
|
||||
{
|
||||
printf("init RX demodulator\n");
|
||||
|
||||
// downmixer oscillator
|
||||
float RADIANS_PER_SAMPLE = ((2.0f*(float)M_PI*(float)FREQUENCY)/(float)caprate);
|
||||
radians_per_sample = ((2.0f*(float)M_PI*(float)FREQUENCY)/(float)caprate);
|
||||
|
||||
dnnco = nco_crcf_create(LIQUID_NCO);
|
||||
nco_crcf_set_phase(dnnco, 0.0f);
|
||||
nco_crcf_set_frequency(dnnco, RADIANS_PER_SAMPLE);
|
||||
nco_crcf_set_frequency(dnnco, radians_per_sample);
|
||||
|
||||
// create pre-decimator
|
||||
decim = firdecim_crcf_create_kaiser(rxPreInterpolfactor, m_predec, As_predec);
|
||||
@@ -259,6 +271,8 @@ void init_demodulator()
|
||||
// if Audio SR is 48000 but caprate is 44100
|
||||
r_OutDivInRatio = (float)((float)caprate / 48000.0);
|
||||
adecim = msresamp_crcf_create(r_OutDivInRatio, As_adecim);
|
||||
|
||||
lsresamp = msresamp_crcf_create((float)(48000.0/44100.0), As_adecim);
|
||||
|
||||
// create symbol tracking synchronizer
|
||||
km_symtrack_cccf_create(ftype_st, k_st, m_st, beta_st, getMod());
|
||||
@@ -268,10 +282,15 @@ void init_demodulator()
|
||||
void close_demodulator()
|
||||
{
|
||||
if(decim != NULL) firdecim_crcf_destroy(decim);
|
||||
if(adecim) msresamp_crcf_destroy(adecim);
|
||||
symtrack = NULL;
|
||||
decim = NULL;
|
||||
if(adecim) msresamp_crcf_destroy(adecim);
|
||||
adecim = NULL;
|
||||
if (lsresamp) msresamp_crcf_destroy(lsresamp);
|
||||
lsresamp = NULL;
|
||||
if (symtrack != NULL) symtrack_cccf_destroy(symtrack);
|
||||
symtrack = NULL;
|
||||
if (dnnco != NULL) nco_crcf_destroy(dnnco);
|
||||
dnnco = NULL;
|
||||
}
|
||||
|
||||
void resetModem()
|
||||
@@ -288,6 +307,33 @@ void make_FFTdata(float f)
|
||||
uint16_t* fft = make_waterfall(f, &fftlen);
|
||||
if (fft != NULL)
|
||||
{
|
||||
// fft data are in fft[] size: 0..fftlen
|
||||
// 10 Hz per value
|
||||
float fdiff = (float)FREQUENCY - actfrequency;
|
||||
// shift spectrum if we are off 1500 Hz
|
||||
int diff10Hz = (int)(fdiff / 10.0);
|
||||
if (diff10Hz != 0)
|
||||
{
|
||||
//printf("%d %f %f %d\n", FREQUENCY, actfrequency, fdiff, diff10Hz);
|
||||
if (diff10Hz < 0)
|
||||
{
|
||||
diff10Hz = -diff10Hz;
|
||||
for (int i = 0; i < (fftlen-diff10Hz); i++)
|
||||
fft[i] = fft[i + diff10Hz];
|
||||
|
||||
for (int i = (fftlen - diff10Hz); i < fftlen; i++)
|
||||
fft[i] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = fftlen-1; i >= diff10Hz; i--)
|
||||
fft[i] = fft[i - diff10Hz];
|
||||
|
||||
for (int i = 0; i < diff10Hz; i++)
|
||||
fft[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t txpl[10000];
|
||||
if (fftlen > (10000 * 2 + 1))
|
||||
{
|
||||
@@ -367,7 +413,29 @@ static int const_idx = 0;
|
||||
if(ret == 0) return 0;
|
||||
|
||||
if (VoiceAudioMode == VOICEMODE_LISTENAUDIOIN)
|
||||
io_ls_write_fifo(f);
|
||||
{
|
||||
if (physRXcaprate == 44100)
|
||||
{
|
||||
// Loudspeaker Audio "ls" works only with 48k
|
||||
// so we have to resample 44k1 to 48k
|
||||
unsigned int num_written = 0;
|
||||
liquid_float_complex in;
|
||||
liquid_float_complex out[100];
|
||||
in.real = f;
|
||||
in.imag = 0;
|
||||
msresamp_crcf_execute(lsresamp, &in, 1, out, &num_written);
|
||||
if (num_written != 0)
|
||||
{
|
||||
for (unsigned int i = 0; i < num_written; i++)
|
||||
{
|
||||
float fout = out[i].real;
|
||||
io_ls_write_fifo(fout);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
io_ls_write_fifo(f);
|
||||
}
|
||||
|
||||
// input volume
|
||||
f *= softwareCAPvolume;
|
||||
@@ -375,7 +443,7 @@ static int const_idx = 0;
|
||||
getMax(f);
|
||||
make_FFTdata(f * 100);
|
||||
|
||||
if (caprate == 44100 && physcaprate == 48000)
|
||||
if (caprate == 44100 && physRXcaprate == 48000)
|
||||
{
|
||||
// the sound card capture for a VAC always works with 48000 because
|
||||
// a VAC cannot be set to a specific cap rate in shared mode
|
||||
@@ -389,7 +457,15 @@ static int const_idx = 0;
|
||||
if (num_written == 0) return 1;
|
||||
f = out.real;
|
||||
}
|
||||
|
||||
|
||||
// if user changed frequency
|
||||
if (radians_per_sample != last_radians_per_sample)
|
||||
{
|
||||
//printf("new QRG. Rad:%f\n", radians_per_sample);
|
||||
nco_crcf_set_frequency(dnnco, radians_per_sample);
|
||||
last_radians_per_sample = radians_per_sample;
|
||||
}
|
||||
|
||||
// downconvert 1,5kHz into baseband, still at soundcard sample rate
|
||||
nco_crcf_step(dnnco);
|
||||
|
||||
|
||||
Executable
+262
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* High Speed modem to transfer data in a 2,7kHz SSB channel
|
||||
* =========================================================
|
||||
* Author: DJ0ABR
|
||||
*
|
||||
* (c) DJ0ABR
|
||||
* www.dj0abr.de
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*
|
||||
* RTTY:
|
||||
* =====
|
||||
* bit/symbol: 1
|
||||
* BW: 170 Hz
|
||||
* carrier: 1500 Hz
|
||||
* speed: 45.45 bits/s
|
||||
* samples/symbol: 33
|
||||
*/
|
||||
|
||||
#include "hsmodem.h"
|
||||
|
||||
#define rtty_CENTERFREQUENCY 1500
|
||||
|
||||
fskmod rtty_mod = NULL;
|
||||
fskdem rtty_dem = NULL;
|
||||
|
||||
unsigned int rtty_m = 1; // bits/symbol
|
||||
const unsigned int rtty_k = 33; // samples/symbol (periods of the 1500 Hz Carrier in one symbol)
|
||||
float rtty_bandwith = (170.0f/2)/ (float)rtty_CENTERFREQUENCY; // 170 Hz spacing normalized to 1500 Hz
|
||||
|
||||
firinterp_crcf rtty_TX_interpolator = NULL;
|
||||
unsigned int rtty_k_SampPerSymb = 20; // 44100 / (4410/2)
|
||||
unsigned int rtty_m_filterDelay_Symbols = 15; // not too short for good filter
|
||||
float rtty_beta_excessBW = 0.2f; // filter excess bandwidth factor
|
||||
float rtty_tau_FracSymbOffset = -0.2f; // fractional symbol offset
|
||||
|
||||
nco_crcf rtty_upnco = NULL;
|
||||
nco_crcf rtty_dnnco = NULL;
|
||||
|
||||
firdecim_crcf rtty_decim = NULL;
|
||||
unsigned int rtty_m_predec = 8; // filter delay
|
||||
float rtty_As_predec = 40.0f; // stop-band att
|
||||
|
||||
void close_rtty();
|
||||
|
||||
void init_rtty()
|
||||
{
|
||||
close_rtty();
|
||||
|
||||
rtty_mod = fskmod_create(rtty_m, rtty_k, rtty_bandwith);
|
||||
rtty_dem = fskdem_create(rtty_m, rtty_k, rtty_bandwith);
|
||||
|
||||
// TX: Interpolator Filter
|
||||
rtty_k_SampPerSymb = caprate / rtty_CENTERFREQUENCY;
|
||||
|
||||
// compute delay
|
||||
while (rtty_tau_FracSymbOffset < 0) rtty_tau_FracSymbOffset += 1.0f; // ensure positive tau
|
||||
float g = rtty_k_SampPerSymb * rtty_tau_FracSymbOffset; // number of samples offset
|
||||
int ds = (int)floorf(g); // additional symbol delay
|
||||
float dt = (g - (float)ds); // fractional sample offset
|
||||
// force dt to be in [0.5,0.5]
|
||||
if (dt > 0.5f)
|
||||
{
|
||||
dt -= 1.0f;
|
||||
ds++;
|
||||
}
|
||||
|
||||
// calculate filter coeffs
|
||||
unsigned int h_len_NumFilterCoeefs = 2 * rtty_k_SampPerSymb * rtty_m_filterDelay_Symbols + 1;
|
||||
float h[4000];
|
||||
if (h_len_NumFilterCoeefs >= 4000)
|
||||
{
|
||||
printf("rtty h in h_len_NumFilterCoeefs too small, need %d\n", h_len_NumFilterCoeefs);
|
||||
return;
|
||||
}
|
||||
liquid_firdes_prototype(LIQUID_FIRFILT_RRC,
|
||||
rtty_k_SampPerSymb,
|
||||
rtty_m_filterDelay_Symbols,
|
||||
rtty_beta_excessBW,
|
||||
dt,
|
||||
h);
|
||||
// create the filter
|
||||
rtty_TX_interpolator = firinterp_crcf_create(rtty_k_SampPerSymb, h, h_len_NumFilterCoeefs);
|
||||
|
||||
// create NCO for upmixing to 1500 Hz
|
||||
float rtty_RADIANS_PER_SAMPLE = ((2.0f * (float)M_PI * (float)rtty_CENTERFREQUENCY) / (float)caprate);
|
||||
rtty_upnco = nco_crcf_create(LIQUID_NCO);
|
||||
nco_crcf_set_phase(rtty_upnco, 0.0f);
|
||||
nco_crcf_set_frequency(rtty_upnco, rtty_RADIANS_PER_SAMPLE);
|
||||
|
||||
rtty_dnnco = nco_crcf_create(LIQUID_NCO);
|
||||
nco_crcf_set_phase(rtty_dnnco, 0.0f);
|
||||
nco_crcf_set_frequency(rtty_dnnco, rtty_RADIANS_PER_SAMPLE);
|
||||
|
||||
rtty_decim = firdecim_crcf_create_kaiser(rtty_k_SampPerSymb, rtty_m_predec, rtty_As_predec);
|
||||
firdecim_crcf_set_scale(rtty_decim, 1.0f / (float)rtty_k_SampPerSymb);
|
||||
}
|
||||
|
||||
void close_rtty()
|
||||
{
|
||||
if (rtty_mod != NULL) fskmod_destroy(rtty_mod);
|
||||
rtty_mod = NULL;
|
||||
if (rtty_TX_interpolator != NULL) firinterp_crcf_destroy(rtty_TX_interpolator);
|
||||
rtty_TX_interpolator = NULL;
|
||||
if (rtty_upnco != NULL) nco_crcf_destroy(rtty_upnco);
|
||||
rtty_upnco = NULL;
|
||||
if (rtty_dnnco != NULL) nco_crcf_destroy(rtty_dnnco);
|
||||
rtty_dnnco = NULL;
|
||||
if (rtty_decim != NULL) firdecim_crcf_destroy(rtty_decim);
|
||||
rtty_decim = NULL;
|
||||
if (rtty_dem != NULL) fskdem_destroy(rtty_dem);
|
||||
rtty_dem = NULL;
|
||||
}
|
||||
|
||||
char text[6] = {"ABCD\n"};
|
||||
int tidx = 0;
|
||||
int bitidx = 1;
|
||||
|
||||
void rtty_tx()
|
||||
{
|
||||
if (rtty_mod == NULL)
|
||||
init_rtty();
|
||||
|
||||
unsigned int sym = (text[tidx] & bitidx) ? 1 : 0;
|
||||
bitidx <<= 1;
|
||||
if (bitidx == 0x0100)
|
||||
{
|
||||
bitidx = 1;
|
||||
tidx++;
|
||||
if (tidx == 6) tidx = 0;
|
||||
}
|
||||
|
||||
liquid_float_complex rtty_txbuf[33+1];
|
||||
|
||||
// gets one symbol at a speed of 45.45
|
||||
fskmod_modulate(rtty_mod, sym, rtty_txbuf);
|
||||
// here we have the complex RTTY signal in baseband
|
||||
// one symbol was expanded to rtty_k periods:
|
||||
// 45.454545 * 33 = 1500 periods
|
||||
|
||||
for (unsigned int i = 0; i < rtty_k; i++)
|
||||
{
|
||||
// resample it to the soundcard rate caprate
|
||||
// interpolate by k_SampPerSymb
|
||||
liquid_float_complex y[40];
|
||||
if (rtty_k_SampPerSymb >= 40)
|
||||
{
|
||||
printf("y in k_SampPerSymb too small, need %d\n", rtty_k_SampPerSymb);
|
||||
return;
|
||||
}
|
||||
|
||||
firinterp_crcf_execute(rtty_TX_interpolator, rtty_txbuf[i], y);
|
||||
// here we have rtty_k_SampPerSymb samples in y[] in the baseband at caprate
|
||||
// speed
|
||||
|
||||
for (unsigned int i = 0; i < rtty_k_SampPerSymb; i++)
|
||||
{
|
||||
// move sample to 1,5kHz carrier
|
||||
nco_crcf_step(rtty_upnco);
|
||||
|
||||
liquid_float_complex c;
|
||||
nco_crcf_mix_up(rtty_upnco, y[i], &c);
|
||||
float usb = c.real + c.imag;
|
||||
|
||||
// speed: 48000
|
||||
// adapt speed to soundcard samplerate
|
||||
int fs;
|
||||
while (1)
|
||||
{
|
||||
fs = io_pb_fifo_freespace(0);
|
||||
// wait until there is space in fifo
|
||||
if (fs > 20000) break;
|
||||
sleep_ms(10);
|
||||
}
|
||||
|
||||
io_pb_write_fifo(usb * 0.2f); // reduce volume and send to soundcard
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RTTY: sample rate HAS TO BE 48000
|
||||
int rtty_rx()
|
||||
{
|
||||
static liquid_float_complex ccol[500];
|
||||
static unsigned int ccol_idx = 0;
|
||||
|
||||
if (rtty_dnnco == NULL) return 0;
|
||||
|
||||
// get one received sample
|
||||
float f;
|
||||
int ret = io_cap_read_fifo(&f);
|
||||
if (ret == 0) return 0;
|
||||
|
||||
if (VoiceAudioMode == VOICEMODE_LISTENAUDIOIN)
|
||||
io_ls_write_fifo(f);
|
||||
|
||||
// input volume
|
||||
f *= softwareCAPvolume;
|
||||
|
||||
//getMax(f);
|
||||
//make_FFTdata(f * 100);
|
||||
|
||||
// downconvert 1,5kHz into baseband, still at soundcard sample rate
|
||||
nco_crcf_step(rtty_dnnco);
|
||||
|
||||
liquid_float_complex in;
|
||||
in.real = f;
|
||||
in.imag = f;
|
||||
liquid_float_complex c;
|
||||
nco_crcf_mix_down(rtty_dnnco, in, &c);
|
||||
|
||||
// c is the actual sample, converted to complex and shifted to baseband
|
||||
|
||||
// this is the first decimator. We need to collect rtty_k_SampPerSymb number of samples
|
||||
// then call execute which will give us one decimated sample
|
||||
ccol[ccol_idx++] = c;
|
||||
if (ccol_idx < rtty_k_SampPerSymb) return 1;
|
||||
ccol_idx = 0;
|
||||
|
||||
// we have rtty_k_SampPerSymb samples in ccol
|
||||
liquid_float_complex y;
|
||||
firdecim_crcf_execute(rtty_decim, ccol, &y);
|
||||
// the output of the pre decimator is exactly one sample in y
|
||||
// ready for demodulation
|
||||
// here we have 1500 samples/s
|
||||
// collect rtty_k (33) samples then demodulate, 1500/33 = 45.45
|
||||
static unsigned int cs = 0;
|
||||
static liquid_float_complex camps[rtty_k];
|
||||
camps[cs] = y;
|
||||
if (++cs < rtty_k) return 1;
|
||||
cs = 0;
|
||||
|
||||
//measure_speed_bps(1);
|
||||
|
||||
unsigned int sym_out = fskdem_demodulate(rtty_dem, camps);
|
||||
|
||||
static int sym = 0;
|
||||
static int symidx = 0;
|
||||
sym |= sym_out << symidx;
|
||||
symidx++;
|
||||
if (symidx == 8)
|
||||
{
|
||||
symidx = 0;
|
||||
printf("%d: %c\n", sym, sym);
|
||||
sym = 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
+3
-3
@@ -522,14 +522,14 @@ int io_init_sound(char *pbname, char *capname)
|
||||
{
|
||||
instream->format = SoundIoFormatS16NE;
|
||||
instream->sample_rate = caprate;
|
||||
physcaprate = caprate;
|
||||
physRXcaprate = caprate;
|
||||
}
|
||||
else
|
||||
{
|
||||
// a VAC needs these settings or it will not work with 44100
|
||||
instream->format = SoundIoFormatFloat32NE;
|
||||
instream->sample_rate = AUDIO_SAMPRATE;
|
||||
physcaprate = AUDIO_SAMPRATE;
|
||||
physRXcaprate = AUDIO_SAMPRATE;
|
||||
}
|
||||
instream->software_latency = latenz;
|
||||
instream->read_callback = read_callback;
|
||||
@@ -548,7 +548,7 @@ int io_init_sound(char *pbname, char *capname)
|
||||
init_audio_result |= 2;
|
||||
|
||||
printf("selected CAPTURE device:\nname:%s\nid :%s\n", capname, capdevid);
|
||||
printf("physical capture rate:%d, logical capture rate:%d\n", physcaprate, caprate);
|
||||
printf("physical capture rate:%d, logical capture rate:%d\n", physRXcaprate, caprate);
|
||||
printf("format: %s\n\n", soundio_format_string(instream->format));
|
||||
|
||||
// the CAP callback is running now
|
||||
|
||||
+1
-2
@@ -157,13 +157,12 @@ void measure_speed_bps(int len)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
elems += len;
|
||||
if (timespan < 1000) return;
|
||||
|
||||
double dspd = elems;
|
||||
dspd = dspd * 1e3 / timespan;
|
||||
speed = meanvalbps((int)dspd);
|
||||
speed = (int)dspd;
|
||||
|
||||
// here we have number of elements after 1s
|
||||
printf(" ======================= %d bit/s\n", speed);
|
||||
|
||||
@@ -166,8 +166,7 @@ void km_symtrack_execute(liquid_float_complex _x, liquid_float_complex* _y, unsi
|
||||
|
||||
/*float fr = nco_crcf_get_frequency(q->nco);
|
||||
float ph = nco_crcf_get_phase(q->nco);
|
||||
|
||||
printf("%10.6f %10.6f %10.6f %10.6f\n", fr, ph, _x.real, _x.imag);*/
|
||||
printf("f:%10.6f ph:%10.6f\n", fr, ph);*/
|
||||
|
||||
* _ny = num_outputs;
|
||||
}
|
||||
|
||||
+14
-13
@@ -26,11 +26,8 @@
|
||||
|
||||
#include "hsmodem.h"
|
||||
|
||||
|
||||
|
||||
|
||||
#define NUMFREQ 12
|
||||
int tunefreq[NUMFREQ] = { 150,420,690,960,1230,1500,1770,2040,2310,2580,2850,3000 };
|
||||
#define NUMFREQ 13
|
||||
int tunefreq[NUMFREQ] = { 150,420,690,960,1230,1500,1770,2040,2310,2580,2850,2890,100 };
|
||||
nco_crcf tunenco[NUMFREQ];
|
||||
uint32_t tuning_runtime = 0;
|
||||
|
||||
@@ -49,7 +46,6 @@ void init_tune()
|
||||
if (tunenco[i] != NULL) nco_crcf_destroy(tunenco[i]);
|
||||
|
||||
// create NCO for frequency
|
||||
printf("tuning: physcaprate:%d\n", physcaprate);
|
||||
float rad_per_sample = ((2.0f * (float)M_PI * (float)tunefreq[i]) / (float)caprate);
|
||||
tunenco[i] = nco_crcf_create(LIQUID_NCO);
|
||||
nco_crcf_set_phase(tunenco[i], 0.0f);
|
||||
@@ -62,7 +58,7 @@ void init_tune()
|
||||
float do_tuning(int send)
|
||||
{
|
||||
if (tunenco == NULL) return 0.0f;
|
||||
if (send < 0 || send > 4) return 0.0f;
|
||||
if (send < 0 || send > 11) return 0.0f;
|
||||
|
||||
float f = 0;
|
||||
if (send == 1)
|
||||
@@ -77,8 +73,8 @@ float do_tuning(int send)
|
||||
}
|
||||
else
|
||||
{
|
||||
nco_crcf_step(tunenco[send-2]);
|
||||
f = nco_crcf_sin(tunenco[send-2]);
|
||||
nco_crcf_step(tunenco[send]);
|
||||
f = nco_crcf_sin(tunenco[send]);
|
||||
}
|
||||
|
||||
// adapt speed to soundcard samplerate
|
||||
@@ -104,10 +100,15 @@ float do_tuning(int send)
|
||||
|
||||
float singleFrequency()
|
||||
{
|
||||
int i = 11; // 3000 Hz
|
||||
|
||||
int /*i = 11; // 2900 Hz
|
||||
if (tunenco[i] == NULL) return 0.0f;
|
||||
|
||||
nco_crcf_step(tunenco[i]);
|
||||
return nco_crcf_sin(tunenco[i]);
|
||||
float f = nco_crcf_sin(tunenco[i]);*/
|
||||
|
||||
i = 12; // 2930 Hz
|
||||
if (tunenco[i] == NULL) return 0.0f;
|
||||
nco_crcf_step(tunenco[i]);
|
||||
float f = nco_crcf_sin(tunenco[i]);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user