From f40a67e1b7ba21f2a6ae277f15f674c5837106ca Mon Sep 17 00:00:00 2001 From: atsunatsu Date: Fri, 7 Aug 2026 20:01:53 +0800 Subject: [PATCH] revert: remove fldigi CW decoder migration, keep Morse Expert --- app/build.gradle.kts | 1 + feature/cw/build.gradle.kts | 26 +- feature/cw/src/main/cpp/CMakeLists.txt | 30 - .../cw/src/main/cpp/fldigi/android_compat.h | 115 - feature/cw/src/main/cpp/fldigi/complex.h | 43 - feature/cw/src/main/cpp/fldigi/cw.cxx | 1940 ---------- feature/cw/src/main/cpp/fldigi/cw.h | 197 - feature/cw/src/main/cpp/fldigi/fftfilt.cxx | 315 -- feature/cw/src/main/cpp/fldigi/fftfilt.h | 78 - feature/cw/src/main/cpp/fldigi/filters.cxx | 551 --- feature/cw/src/main/cpp/fldigi/filters.h | 183 - feature/cw/src/main/cpp/fldigi/gfft.h | 3392 ----------------- feature/cw/src/main/cpp/fldigi/mbuffer.h | 258 -- feature/cw/src/main/cpp/fldigi/modem.h | 160 - feature/cw/src/main/cpp/fldigi/morse.cxx | 314 -- feature/cw/src/main/cpp/fldigi/morse.h | 58 - feature/cw/src/main/cpp/fldigi/view_cw.h | 24 - feature/cw/src/main/cpp/fldigi_cw_jni.cpp | 88 - .../look4sat/feature/cw/CwDecodeScreen.kt | 5 +- .../look4sat/feature/cw/CwSettingsDialog.kt | 34 +- .../look4sat/feature/cw/FldigiCwController.kt | 205 - .../look4sat/feature/cw/FldigiNative.kt | 23 - .../feature/radar/TransceiversPage.kt | 4 +- 23 files changed, 23 insertions(+), 8021 deletions(-) delete mode 100644 feature/cw/src/main/cpp/CMakeLists.txt delete mode 100644 feature/cw/src/main/cpp/fldigi/android_compat.h delete mode 100644 feature/cw/src/main/cpp/fldigi/complex.h delete mode 100644 feature/cw/src/main/cpp/fldigi/cw.cxx delete mode 100644 feature/cw/src/main/cpp/fldigi/cw.h delete mode 100644 feature/cw/src/main/cpp/fldigi/fftfilt.cxx delete mode 100644 feature/cw/src/main/cpp/fldigi/fftfilt.h delete mode 100644 feature/cw/src/main/cpp/fldigi/filters.cxx delete mode 100644 feature/cw/src/main/cpp/fldigi/filters.h delete mode 100644 feature/cw/src/main/cpp/fldigi/gfft.h delete mode 100644 feature/cw/src/main/cpp/fldigi/mbuffer.h delete mode 100644 feature/cw/src/main/cpp/fldigi/modem.h delete mode 100644 feature/cw/src/main/cpp/fldigi/morse.cxx delete mode 100644 feature/cw/src/main/cpp/fldigi/morse.h delete mode 100644 feature/cw/src/main/cpp/fldigi/view_cw.h delete mode 100644 feature/cw/src/main/cpp/fldigi_cw_jni.cpp delete mode 100644 feature/cw/src/main/java/com/rtbishop/look4sat/feature/cw/FldigiCwController.kt delete mode 100644 feature/cw/src/main/java/com/rtbishop/look4sat/feature/cw/FldigiNative.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2c2085ca..649b3400 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -6,6 +6,7 @@ android { namespace = libs.versions.packageName.get() defaultConfig { applicationId = "cn.ba7opf.look4sat" + ndk { abiFilters.add("armeabi-v7a") } } signingConfigs { create("release") { diff --git a/feature/cw/build.gradle.kts b/feature/cw/build.gradle.kts index 7e6f4c11..3a781ca9 100644 --- a/feature/cw/build.gradle.kts +++ b/feature/cw/build.gradle.kts @@ -7,24 +7,13 @@ plugins { android { namespace = "com.rtbishop.look4sat.feature.cw" - ndkVersion = "25.2.9519653" compileOptions { encoding = "UTF-8" } + // 照搬 Morse Expert 1.15: native 解码器仅 armeabi-v7a defaultConfig { - // fldigi CW 解码器: 支持 arm64-v8a + armeabi-v7a 双架构 ndk { - abiFilters += listOf("arm64-v8a", "armeabi-v7a") - } - externalNativeBuild { - cmake { - cppFlags += "-std=c++17" - } - } - } - externalNativeBuild { - cmake { - path = file("src/main/cpp/CMakeLists.txt") + abiFilters += listOf("armeabi-v7a") } } } @@ -37,4 +26,13 @@ androidComponents { project.layout.projectDirectory.file("proguard-rules.pro") ) } -} \ No newline at end of file +} + +dependencies { + implementation("androidx.constraintlayout:constraintlayout:2.2.1") +} + +// 照搬的 Java 源码含中文注释, 强制 UTF-8 编译(compileOptions 在部分 AGP 版本不生效) +tasks.withType().configureEach { + options.encoding = "UTF-8" +} diff --git a/feature/cw/src/main/cpp/CMakeLists.txt b/feature/cw/src/main/cpp/CMakeLists.txt deleted file mode 100644 index c62599aa..00000000 --- a/feature/cw/src/main/cpp/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -cmake_minimum_required(VERSION 3.22.1) -project(fldigi_cw) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -# 禁用 ANR 检测器等不必要的 Android 特性 -set(CMAKE_ANDROID_EXCEPTIONS ON) - -add_library(fldigi_cw SHARED - fldigi_cw_jni.cpp - fldigi/cw.cxx - fldigi/morse.cxx - fldigi/fftfilt.cxx - fldigi/filters.cxx -) - -target_include_directories(fldigi_cw PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/fldigi -) - -target_compile_definitions(fldigi_cw PRIVATE - FLDIGI_ANDROID -) - -target_link_libraries(fldigi_cw - log - android -) \ No newline at end of file diff --git a/feature/cw/src/main/cpp/fldigi/android_compat.h b/feature/cw/src/main/cpp/fldigi/android_compat.h deleted file mode 100644 index 6d2467a0..00000000 --- a/feature/cw/src/main/cpp/fldigi/android_compat.h +++ /dev/null @@ -1,115 +0,0 @@ -// ---------------------------------------------------------------------------- -// android_compat.h -- fldigi desktop compatibility stubs for Android -// Replaces global variables that fldigi defines in fl_digi.h, configuration.h, etc. -// ---------------------------------------------------------------------------- -#ifndef ANDROID_COMPAT_H -#define ANDROID_COMPAT_H - -#include - -// Waterfall stub -struct waterfall_stub { - double Carrier() { return 700.0; } - bool Reverse() { return false; } - bool USB() { return true; } - void Bandwidth(int) {} -}; -extern waterfall_stub* wf; - -// progdefaults - fldigi global configuration -struct AndroidProgDefaults { - int CWspeed = 18; - double CWbandwidth = 200.0; - double CWfarnsworth = 18; - double CWupper = 0.8; - double CWlower = 0.2; - bool CWmfilt = true; - bool CWtrack = true; - int CWsweetspot = 700; - int CWnoise = '*'; - int CWrisetime = 4; - int QSKshape = 0; - int CWdash2dot = 3; - int CW_cal_speed = 18; - bool CWusefarnsworth = false; - bool use_KNWDkeying = false; - bool use_ELCTkeying = false; - bool use_ICOMkeying = false; - bool use_YAESUkeying = false; - int CATkeying_compensation = 0; - bool StartAtSweetSpot = false; - bool CW_use_paren = false; - std::string CW_prosigns; - bool pretone = false; - bool use_nanoIO = false; - bool rx_lowercase = false; - bool CWuseSOMdecoding = true; - int CW_bandwidth = 200; - int CW_upper = 80; - int CW_lower = 20; - - // Additional fields referenced by cw.cxx - int CWrange = 10; - int CWlowerlimit = 5; - int CWupperlimit = 60; - int CWpre = 0; - int CWpost = 0; - int CWkeycomp = 0; - int cwrx_attack = 0; - int cwrx_decay = 0; - int defCWspeed = 18; - int QSK = 0; - int QSKamp = 0; - int QSKfrequency = 0; - int QSKrisetime = 0; - bool CW_KEYLINE = false; - bool CW_KEYLINE_on_cat_port = false; - bool CW_KEYLINE_on_ptt_port = false; - bool PTT_KEYLINE = false; - bool use_FLRIGkeying = false; - int BaudRate = 0; - std::string CW_KEYLINE_serial_port_name; -}; -extern AndroidProgDefaults progdefaults; - -// NanoIO globals -extern bool use_nanoIO; -void set_nanoWPM(int wpm); - -// UI/status stubs (fldigi desktop helpers, no-op on Android) -void put_cwRcvWPM(int); -void put_MODEstatus(const char*, ...); -void set_scope_xaxis_1(double); -void set_scope_xaxis(double); -template -void set_scope(mbuffer&, int, bool) {} -void set_nanoCW(); -void update_Status(); - -// Fldigi math helpers -#define TWOPI (2.0 * M_PI) -inline double decayavg(double average, double input, int weight) { - if (weight <= 1) return input; - return ((input - average) / (double)weight) + average; -} - -// progStatus -struct AndroidProgStatus { - int carrier = 0; - bool WK_online = false; - bool sqlonoff = false; - double sldrSquelchValue = 0.0; - bool show_channels = false; -}; -extern AndroidProgStatus progStatus; - -// Misc helpers that fldigi provides via misc.h / status.h / etc. -void set_scope_mode(int); -void put_rx_char(int c); -void put_echo_char(int c); - -// Time helpers -double zmsec(); -void MilliSleep(int); - -#endif \ No newline at end of file diff --git a/feature/cw/src/main/cpp/fldigi/complex.h b/feature/cw/src/main/cpp/fldigi/complex.h deleted file mode 100644 index 312313a6..00000000 --- a/feature/cw/src/main/cpp/fldigi/complex.h +++ /dev/null @@ -1,43 +0,0 @@ -// ---------------------------------------------------------------------------- -// complex.h -- Complex arithmetic -// -// Copyright (C) 2006-2008 -// Dave Freese, W1HKJ -// Copyright (C) 2008 -// Stelios Bounanos, M0GLD -// -// This file is part of fldigi. -// -// Fldigi 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. -// -// Fldigi 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 fldigi. If not, see . -// ---------------------------------------------------------------------------- - -#ifndef _COMPLEX_H -#define _COMPLEX_H - -#include -#include - -typedef std::complex cmplx; - -inline cmplx cmac (const cmplx *a, const cmplx *b, int ptr, int len) { - cmplx z; - ptr %= len; - for (int i = 0; i < len; i++) { - z += a[i] * b[ptr]; - ptr = (ptr + 1) % len; - } - return z; -} - -#endif diff --git a/feature/cw/src/main/cpp/fldigi/cw.cxx b/feature/cw/src/main/cpp/fldigi/cw.cxx deleted file mode 100644 index 5be1d3f6..00000000 --- a/feature/cw/src/main/cpp/fldigi/cw.cxx +++ /dev/null @@ -1,1940 +0,0 @@ -// ---------------------------------------------------------------------------- -// cw.cxx -- morse code modem -// -// Copyright (C) 2006-2010 -// Dave Freese, W1HKJ -// (C) Mauri Niininen, AG1LE -// -// This file is part of fldigi. Adapted from code contained in gmfsk source code -// distribution. -// gmfsk Copyright (C) 2001, 2002, 2003 -// Tomi Manninen (oh2bns@sral.fi) -// Copyright (C) 2004 -// Lawrence Glaister (ve7it@shaw.ca) -// -// Fldigi 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. -// -// Fldigi 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 fldigi. If not, see . -// ---------------------------------------------------------------------------- - -//#include (removed for Android) - -#include -#include -#include -#include -#include -#include -#include - -//#include "timeops.h" (removed for Android) -#ifdef __MINGW32__// disabled for Android -//#include "compat.h" (removed) -#endif - -#if 0 // HAVE_CLOCK_GETTIME disabled for Android -# ifdef __APPLE__ -# include -# endif -#endif - -//#include "digiscope.h" (removed) -//#include "waterfall.h" (removed) -//#include "fl_digi.h" (removed) -#include "fftfilt.h" -//#include "serial.h" (removed) -//#include "ptt.h" (removed) -#include "filters.h" - -#include "cw.h" -#include "android_compat.h" - -#ifndef BENCHMARK_MODE -#define BENCHMARK_MODE 0 -#endif -//#include "misc.h" (removed) -//#include "configuration.h" (removed) -//#include "confdialog.h" (removed) -//#include "status.h" (removed) -//#include "debug.h" (removed) -//#include "FTextRXTX.h" (removed) -#include "modem.h" - -//#include "qrunner.h" (removed) - -//#include "winkeyer.h" (removed) -//#include "nanoIO.h" (removed) -//#include "KYkeying.h" (removed) -//#include "ICOMkeying.h" (removed) -//#include "YAESUkeying.h" (removed) - -//#include "audio_alert.h" (removed) - -#define XMT_FILT_LEN 256 -#define QSK_DELAY_LEN 4*XMT_FILT_LEN -#define CW_FFT_SIZE 2048 // must be a factor of 2 - -static double nano_d2d = 0; -static int nano_wpm = 0; - -const cw::SOM_TABLE cw::som_table[] = { - /* Prosigns */ - {"-...-", {1.0, 0.33, 0.33, 0.33, 1.0, 0, 0} }, - {".-.-", { 0.33, 1.0, 0.33, 1.0, 0, 0, 0} }, - {".-...", { 0.33, 1.0, 0.33, 0.33, 0.33, 0, 0} }, - {".-.-.", { 0.33, 1.0, 0.33, 1.0, 0.33, 0, 0} }, - {"...-.-", { 0.33, 0.33, 0.33, 1.0, 0.33, 1.0, 0} }, - {"-.--.", {1.0, 0.33, 1.0, 1.0, 0.33, 0, 0} }, - {"..-.-", { 0.33, 0.33, 1.0, 0.33, 1.0, 0, 0} }, - {"....--", { 0.33, 0.33, 0.33, 0.33, 1.0, 1.0, 0} }, - {"...-.", { 0.33, 0.33, 0.33, 1.0, 0.33, 0, 0} }, - /* ASCII 7bit letters */ - {".-", { 0.33, 1.0, 0, 0, 0, 0, 0} }, - {"-...", {1.0, 0.33, 0.33, 0.33, 0, 0, 0} }, - {"-.-.", {1.0, 0.33, 1.0, 0.33, 0, 0, 0} }, - {"-..", {1.0, 0.33, 0.33, 0, 0, 0, 0} }, - {".", { 0.33, 0, 0, 0, 0, 0, 0} }, - {"..-.", { 0.33, 0.33, 1.0, 0.33, 0, 0, 0} }, - {"--.", {1.0, 1.0, 0.33, 0, 0, 0, 0} }, - {"....", { 0.33, 0.33, 0.33, 0.33, 0, 0, 0} }, - {"..", { 0.33, 0.33, 0, 0, 0, 0, 0} }, - {".---", { 0.33, 1.0, 1.0, 1.0, 0, 0, 0} }, - {"-.-", {1.0, 0.33, 1.0, 0, 0, 0, 0} }, - {".-..", { 0.33, 1.0, 0.33, 0.33, 0, 0, 0} }, - {"--", {1.0, 1.0, 0, 0, 0, 0, 0} }, - {"-.", {1.0, 0.33, 0, 0, 0, 0, 0} }, - {"---", {1.0, 1.0, 1.0, 0, 0, 0, 0} }, - {".--.", { 0.33, 1.0, 1.0, 0.33, 0, 0, 0} }, - {"--.-", {1.0, 1.0, 0.33, 1.0, 0, 0, 0} }, - {".-.", { 0.33, 1.0, 0.33, 0, 0, 0, 0} }, - {"...", { 0.33, 0.33, 0.33, 0, 0, 0, 0} }, - {"-", {1.0, 0, 0, 0, 0, 0, 0} }, - {"..-", { 0.33, 0.33, 1.0, 0, 0, 0, 0} }, - {"...-", { 0.33, 0.33, 0.33, 1.0, 0, 0, 0} }, - {".--", { 0.33, 1.0, 1.0, 0, 0, 0, 0} }, - {"-..-", {1.0, 0.33, 0.33, 1.0, 0, 0, 0} }, - {"-.--", {1.0, 0.33, 1.0, 1.0, 0, 0, 0} }, - {"--..", {1.0, 1.0, 0.33, 0.33, 0, 0, 0} }, - /* Numerals */ - {"-----", {1.0, 1.0, 1.0, 1.0, 1.0, 0, 0} }, - {".----", { 0.33, 1.0, 1.0, 1.0, 1.0, 0, 0} }, - {"..---", { 0.33, 0.33, 1.0, 1.0, 1.0, 0, 0} }, - {"...--", { 0.33, 0.33, 0.33, 1.0, 1.0, 0, 0} }, - {"....-", { 0.33, 0.33, 0.33, 0.33, 1.0, 0, 0} }, - {".....", { 0.33, 0.33, 0.33, 0.33, 0.33, 0, 0} }, - {"-....", {1.0, 0.33, 0.33, 0.33, 0.33, 0, 0} }, - {"--...", {1.0, 1.0, 0.33, 0.33, 0.33, 0, 0} }, - {"---..", {1.0, 1.0, 1.0, 0.33, 0.33, 0, 0} }, - {"----.", {1.0, 1.0, 1.0, 1.0, 0.33, 0, 0} }, - /* Punctuation */ - {".-..-.", { 0.33, 1.0, 0.33, 0.33, 1.0, 0.33, 0} }, - {".----.", { 0.33, 1.0, 1.0, 1.0, 1.0, 0.33, 0} }, - {"...-..-", { 0.33, 0.33, 0.33, 1.0, 0.33, 0.33, 1.0} }, - {"-.---.", {1.0, 0.33, 1.0, 1.0, 0.33, 0, 0} }, - {"-.--.-", {1.0, 0.33, 1.0, 1.0, 0.33, 1.0, 0} }, - {"--..--", {1.0, 1.0, 0.33, 0.33, 1.0, 1.0, 0} }, - {"-....-", {1.0, 0.33, 0.33, 0.33, 0.33, 1.0, 0} }, - {".-.-.-", { 0.33, 1.0, 0.33, 1.0, 0.33, 1.0, 0} }, - {"-..-.", {1.0, 0.33, 0.33, 1.0, 0.33, 0, 0} }, - {"---...", {1.0, 1.0, 1.0, 0.33, 0.33, 0.33, 0} }, - {"-.-.-.", {1.0, 0.33, 1.0, 0.33, 1.0, 0.33, 0} }, - {"..--..", { 0.33, 0.33, 1.0, 1.0, 0.33, 0.33, 0} }, - {"..--.-", { 0.33, 0.33, 1.0, 1.0, 0.33, 1.0, 0} }, - {".--.-.", { 0.33, 1.0, 1.0, 0.33, 1.0, 0.33, 0} }, - {"-.-.--", {1.0, 0.33, 1.0, 0.33, 1.0, 1.0, 0} }, - - {".-.-", {0.33, 1.0, 0.33, 1.0, 0, 0 , 0} }, // A umlaut, A aelig - {".--.-", {0.33, 1.0, 1.0, 0.33, 1.0, 0, 0 } }, // A ring - {"-.-..", {1.0, 0.33, 1.0, 0.33, 0.33, 0, 0} }, // C cedilla - {".-..-", {0.33, 1.0, 0.33, 0.33, 1.0, 0, 0} }, // E grave - {"..-..", {0.33, 0.33, 1.0, 0.33, 0.33, 0, 0} }, // E acute - {"---.", {1.0, 1.0, 1.0, 0.33, 0, 0, 0} }, // O acute, O umlat, O slash - {"--.--", {1.0, 1.0, 0.33, 1.0, 1.0, 0, 0} }, // N tilde - {"..--", {0.33, 0.33, 1.0, 1.0, 0, 0, 0} }, // U umlaut, U circ - - {"", {0.0}} -}; - -int cw::normalize(float *v, int n, int twodots) -{ - if( n == 0 ) return 0 ; - - float max = v[0]; - float min = v[0]; - int j; - - /* find max and min values */ - for (j=1; j max) max = vj; - else if (vj < min) min = vj; - } - /* all values 0 - no need to normalize or decode */ - if (max == 0.0) return 0; - - /* scale values between [0,1] -- if Max longer than 2 dots it was "dah" and should be 1.0, otherwise it was "dit" and should be 0.33 */ - float ratio = (max > twodots) ? 1.0 : 0.33 ; - ratio /= max ; - for (j=0; j diffsf) break; - } - - /* If distance is smaller than previous distances */ - if (difference < diffsf) { - winner = n; - diffsf = difference; - } - } - - std::string sc; - if (!som_table[winner].rpr.empty()) { - sc = morse->rx_lookup(som_table[winner].rpr); - if (sc.empty()) - sc = (progdefaults.CW_noise == '*' ? "*" : - progdefaults.CW_noise == '_' ? "_" : - progdefaults.CW_noise == ' ' ? " " : ""); - } else - sc = (progdefaults.CW_noise == '*' ? "*" : - progdefaults.CW_noise == '_' ? "_" : - progdefaults.CW_noise == ' ' ? " " : ""); - return sc; -} - -void cw::tx_init() -{ - phaseacc = 0; - lastsym = 0; - qskphase = 0; - if (progdefaults.pretone) pretone(); - - symbols = 0; - acc_symbols = 0; - ovhd_symbols = 0; - - maxval = 0.0; -} - -void cw::rx_init() -{ - cw_receive_state = RS_IDLE; - smpl_ctr = 0; - cw_rr_current = 0; - cw_ptr = 0; - agc_peak = 0; - // set_scope_mode removed for Android - - update_Status(); - usedefaultWPM = false; - scope_clear = true; - - viewcw.restart(); -} - -void cw::init() -{ - bool wfrev = wf ? wf->Reverse() : false; - bool wfsb = wf ? wf->USB() : true; - reverse = wfrev ^ !wfsb; - - if (progdefaults.StartAtSweetSpot) - set_freq(progdefaults.CWsweetspot); - else if (progStatus.carrier != 0) { - set_freq(progStatus.carrier); -#if !BENCHMARK_MODE - progStatus.carrier = 0; -#endif - } else - set_freq(wf ? wf->Carrier() : 700.0); - - trackingfilter->reset(); - two_dots = (long int)trackingfilter->run(2 * cw_send_dot_length); - put_cwRcvWPM(cw_send_speed); - - memset(outbuf, 0, OUTBUFSIZE*sizeof(*outbuf)); - memset(qskbuf, 0, OUTBUFSIZE*sizeof(*qskbuf)); - - morse->init(); - use_paren = progdefaults.CW_use_paren; - prosigns = progdefaults.CW_prosigns; - - rx_init(); - - stopflag = false; - maxval = 0; - - if (use_nanoIO) // set_nanoCW() removed - -} - -cw::~cw() { - if (cw_FFT_filter) delete cw_FFT_filter; - if (bitfilter) delete bitfilter; - if (trackingfilter) delete trackingfilter; - // stop_cwio_thread() removed for Android -} - -cw::cw() : modem() -{ - cap |= CAP_BW; - - mode = MODE_CW; - freqlock = false; - usedefaultWPM = false; - frequency = progdefaults.CWsweetspot; - tx_frequency = get_txfreq(); - risetime = progdefaults.CWrisetime; - QSKshape = progdefaults.QSKshape; - - cw_ptr = 0; - clrcount = CLRCOUNT; - - samplerate = CW_SAMPLERATE; - fragmentsize = CWMaxSymLen; - - wpm = cw_speed = progdefaults.CWspeed; - bandwidth = progdefaults.CWbandwidth; - - cw_send_speed = cw_speed; - cw_receive_speed = cw_speed; - two_dots = 2 * KWPM / cw_speed; - cw_noise_spike_threshold = two_dots / 4; - cw_send_dot_length = KWPM / cw_send_speed; - cw_send_dash_length = 3 * cw_send_dot_length; - symbollen = (int)round(samplerate * 1.2 / progdefaults.CWspeed); // transmit char rate - fsymlen = (int)round(samplerate * 1.2 / progdefaults.CWfarnsworth); // transmit word rate - - rx_rep_buf.clear(); - -// block of variables that get updated each time speed changes - pipesize = (22 * samplerate * 12) / (progdefaults.CWspeed * 160); - if (pipesize < 0) pipesize = 512; - if (pipesize > MAX_PIPE_SIZE) pipesize = MAX_PIPE_SIZE; - - cwTrack = true; - phaseacc = 0.0; - FFTphase = 0.0; - FFTvalue = 0.0; - pipeptr = 0; - clrcount = 0; - - upper_threshold = progdefaults.CWupper; - lower_threshold = progdefaults.CWlower; - for (int i = 0; i < MAX_PIPE_SIZE; clearpipe[i++] = 0.0); - - agc_peak = 1.0; - in_replay = 0; - - use_matched_filter = progdefaults.CWmfilt; - - bandwidth = progdefaults.CWbandwidth; - if (use_matched_filter) - progdefaults.CWbandwidth = bandwidth = 5.0 * progdefaults.CWspeed / 1.2; - - cw_FFT_filter = new fftfilt(1.0 * progdefaults.CWbandwidth / samplerate, CW_FFT_SIZE); - - int bfv = symbollen / ( 2 * DEC_RATIO); - if (bfv < 1) bfv = 1; - - bitfilter = new Cmovavg(bfv); - - trackingfilter = new Cmovavg(TRACKING_FILTER_SIZE); - - create_edges(); - - nano_wpm = progdefaults.CWspeed; - nano_d2d = progdefaults.CWdash2dot; - - sync_parameters(); - // REQ removed for Android - // REQ removed for Android - update_Status(); - - synchscope = 50; - noise_floor = 1.0; - sig_avg = 0.0; - - cal_wpm = 20; - - // start_cwio_thread() removed for Android - -} - -// SHOULD ONLY BE CALLED FROM THE rx_processing loop -void cw::reset_rx_filter() -{ - if (use_matched_filter != progdefaults.CWmfilt || - cw_speed != progdefaults.CWspeed || - (bandwidth != progdefaults.CWbandwidth && !use_matched_filter)) { - - use_matched_filter = progdefaults.CWmfilt; - cw_send_speed = cw_speed = progdefaults.CWspeed; - - if (use_matched_filter) - progdefaults.CWbandwidth = bandwidth = 5.0 * progdefaults.CWspeed / 1.2; - else - bandwidth = progdefaults.CWbandwidth; - - cw_FFT_filter->create_lpf(1.0 * bandwidth / samplerate); - FFTphase = 0; - - // REQ(static_cast(&waterfall::Bandwidth), wf, (int)bandwidth); // removed for Android - // REQ(static_cast(&Fl_Value_Slider2::value), sldrCWbandwidth, (int)bandwidth); // removed for Android - - pipesize = (22 * samplerate * 12) / (progdefaults.CWspeed * 160); - if (pipesize < 0) pipesize = 512; - if (pipesize > MAX_PIPE_SIZE) pipesize = MAX_PIPE_SIZE; - - two_dots = 2 * KWPM / cw_speed; - cw_noise_spike_threshold = two_dots / 4; - cw_send_dot_length = KWPM / cw_send_speed; - cw_send_dash_length = 3 * cw_send_dot_length; - symbollen = (int)round(samplerate * 1.2 / progdefaults.CWspeed); - fsymlen = (int)round(samplerate * 1.2 / progdefaults.CWfarnsworth); - - phaseacc = 0.0; - FFTphase = 0.0; - FFTvalue = 0.0; - pipeptr = 0; - clrcount = 0; - smpl_ctr = 0; - - rx_rep_buf.clear(); - - int bfv = symbollen / ( 2 * DEC_RATIO); - if (bfv < 1) bfv = 1; - - bitfilter->setLength(bfv); - - siglevel = 0; - - } - -} - -// sync_parameters() -// Synchronize the dot, dash, end of element, end of character, and end -// of word timings and ranges to new values of Morse speed, or receive tolerance. - -void cw::sync_transmit_parameters() -{ -// wpm = usedefaultWPM ? progdefaults.defCWspeed : progdefaults.CWspeed; - fwpm = progdefaults.CWfarnsworth; - - cw_send_dot_length = KWPM / progdefaults.CWspeed; - cw_send_dash_length = 3 * cw_send_dot_length; - - nusymbollen = (int)round(samplerate * 1.2 / progdefaults.CWspeed); - nufsymlen = (int)round(samplerate * 1.2 / fwpm); - - if (symbollen != nusymbollen || - nufsymlen != fsymlen || - risetime != progdefaults.CWrisetime || - QSKshape != progdefaults.QSKshape) { - risetime = progdefaults.CWrisetime; - QSKshape = progdefaults.QSKshape; - symbollen = nusymbollen; - fsymlen = nufsymlen; - create_edges(); - } -} - -void cw::sync_parameters() -{ - sync_transmit_parameters(); - - if (use_nanoIO) { - if (nano_wpm != progdefaults.CWspeed) { - nano_wpm = progdefaults.CWspeed; - set_nanoWPM(progdefaults.CWspeed); - } - if (nano_d2d != progdefaults.CWdash2dot) { - nano_d2d = progdefaults.CWdash2dot; - set_nano_dash2dot(progdefaults.CWdash2dot); - } - } - -// check if user changed the tracking or the cw default speed - if ((cwTrack != progdefaults.CWtrack) || - (cw_send_speed != progdefaults.CWspeed)) { - trackingfilter->reset(); - two_dots = 2 * cw_send_dot_length; - put_cwRcvWPM(cw_send_speed); - } - cwTrack = progdefaults.CWtrack; - cw_send_speed = progdefaults.CWspeed; - -// Receive parameters: - lowerwpm = cw_send_speed - progdefaults.CWrange; - upperwpm = cw_send_speed + progdefaults.CWrange; - if (lowerwpm < progdefaults.CWlowerlimit) - lowerwpm = progdefaults.CWlowerlimit; - if (upperwpm > progdefaults.CWupperlimit) - upperwpm = progdefaults.CWupperlimit; - cw_lower_limit = 2 * KWPM / upperwpm; - cw_upper_limit = 2 * KWPM / lowerwpm; - - if (cwTrack) - cw_receive_speed = KWPM / (two_dots / 2); - else { - cw_receive_speed = cw_send_speed; - two_dots = 2 * cw_send_dot_length; - } - - if (cw_receive_speed > 0) - cw_receive_dot_length = KWPM / cw_receive_speed; - else - cw_receive_dot_length = KWPM / 5; - - cw_receive_dash_length = 3 * cw_receive_dot_length; - - cw_noise_spike_threshold = cw_receive_dot_length / 2; - -} - - -//======================================================================= -// cw_update_tracking() -//======================================================================= - -inline void cw::update_tracking(int dur_1, int dur_2) -{ -static int min_dot = KWPM / 200; -static int max_dash = 3 * KWPM / 5; - if ((dur_1 > dur_2) && (dur_1 > 4 * dur_2)) return; - if ((dur_2 > dur_1) && (dur_2 > 4 * dur_1)) return; - if (dur_1 < min_dot || dur_2 < min_dot) return; - if (dur_2 > max_dash || dur_2 > max_dash) return; - - two_dots = trackingfilter->run((dur_1 + dur_2) / 2); - - sync_parameters(); -} - -void cw::update_Status() -{ - put_MODEstatus("CW %s Rx %d", usedefaultWPM ? "*" : " ", cw_receive_speed); -} - -//======================================================================= -//update_syncscope() -//Routine called to update the display on the sync scope display. -//For CW this is an o scope pattern that shows the cw data streacwTrackm. -//======================================================================= -// - -void cw::update_syncscope() -{ - if (pipesize < 0 || pipesize > MAX_PIPE_SIZE) - return; - - for (int i = 0; i < pipesize; i++) - scopedata[i] = 0.96*pipe[i]+0.02; - - set_scope_xaxis_1(siglevel); - - set_scope(scopedata, pipesize, true); - scopedata.next(); // change buffers - - clrcount = CLRCOUNT; - put_cwRcvWPM(cw_receive_speed); - update_Status(); -} - -void cw::clear_syncscope() -{ - set_scope_xaxis_1(siglevel); - - set_scope(clearpipe, pipesize, false); - clrcount = CLRCOUNT; -} - -cmplx cw::mixer(cmplx in) -{ - cmplx z (cos(phaseacc), sin(phaseacc)); - z = z * in; - - phaseacc += TWOPI * frequency / samplerate; - if (phaseacc > TWOPI) phaseacc -= TWOPI; - - return z; -} - -//===================================================================== -// cw_rxprocess() -// Called with a block (size SCBLOCKSIZE samples) of audio. -// -//====================================================================== - -void cw::decode_stream(double value) -{ - std::string sc; - std::string somc; - int attack = 0; - int decay = 0; - switch (progdefaults.cwrx_attack) { - case 0: attack = 400; break;//100; break; - case 1: default: attack = 200; break;//50; break; - case 2: attack = 100;//25; - } - switch (progdefaults.cwrx_decay) { - case 0: decay = 2000; break;//1000; break; - case 1: default : decay = 1000; break;//500; break; - case 2: decay = 500;//250; - } - - sig_avg = decayavg(sig_avg, value, decay); - - if (value < sig_avg) { - if (value < noise_floor) - noise_floor = decayavg(noise_floor, value, attack); - else - noise_floor = decayavg(noise_floor, value, decay); - } - if (value > sig_avg) { - if (value > agc_peak) - agc_peak = decayavg(agc_peak, value, attack); - else - agc_peak = decayavg(agc_peak, value, decay); - } - - float norm_noise = noise_floor / agc_peak; - float norm_sig = sig_avg / agc_peak; - siglevel = norm_sig; - - if (agc_peak) - value /= agc_peak; - else - value = 0; - - metric = 0.8 * metric; - if ((noise_floor > 1e-4) && (noise_floor < sig_avg)) - metric += 0.2 * std::clamp(2.5 * (20*log10(sig_avg / noise_floor)) , 0, 100); - - float diff = (norm_sig - norm_noise); - - progdefaults.CWupper = norm_sig - 0.2 * diff; - progdefaults.CWlower = norm_noise + 0.7 * diff; - - pipe[pipeptr] = value; - if (++pipeptr == pipesize) pipeptr = 0; - - if (!progStatus.sqlonoff || metric > progStatus.sldrSquelchValue ) { -// Power detection using hysterisis detector -// upward trend means tone starting - if ((value > progdefaults.CWupper) && (cw_receive_state != RS_IN_TONE)) { - handle_event(CW_KEYDOWN_EVENT, sc); - } -// downward trend means tone stopping - if ((value < progdefaults.CWlower) && (cw_receive_state == RS_IN_TONE)) { - handle_event(CW_KEYUP_EVENT, sc); - } - } - - if (handle_event(CW_QUERY_EVENT, sc) == CW_SUCCESS) { - update_syncscope(); - synchscope = 100; - if (progdefaults.CWuseSOMdecoding) { - somc = find_winner(cw_buffer, two_dots); - if (!somc.empty()) - for (size_t n = 0; n < somc.length(); n++) - rx_text_buffer += somc[n]; - cw_ptr = 0; - memset(cw_buffer, 0, sizeof(cw_buffer)); - } else { - for (size_t n = 0; n < sc.length(); n++) - rx_text_buffer += sc[n]; - } - } else if (--synchscope == 0) { - synchscope = 25; - update_syncscope(); - } - -} - -void cw::rx_FFTprocess(const double *buf, int len) -{ - cmplx z, *zp; - int n; - - while (len-- > 0) { - - z = cmplx ( *buf * cos(FFTphase), *buf * sin(FFTphase) ); - FFTphase += TWOPI * frequency / samplerate; - if (FFTphase > TWOPI) FFTphase -= TWOPI; - - buf++; - - n = cw_FFT_filter->run(z, &zp); // n = 0 or filterlen/2 - - if (!n) continue; - - for (int i = 0; i < n; i++) { -// update the basic sample counter used for morse timing - ++smpl_ctr; - - if (smpl_ctr % DEC_RATIO) continue; // decimate by DEC_RATIO - -// demodulate - FFTvalue = abs(zp[i]); - FFTvalue = bitfilter->run(FFTvalue); - - decode_stream(FFTvalue); - - } // for (i =0; i < n ... - - } //while (len-- > 0) -} - -static bool cwprocessing = false; - -int cw::rx_process(const double *buf, int len) -{ - if (use_paren != progdefaults.CW_use_paren || - prosigns != progdefaults.CW_prosigns) { - use_paren = progdefaults.CW_use_paren; - prosigns = progdefaults.CW_prosigns; - morse->init(); - } - - if (cwprocessing) - return 0; - - cwprocessing = true; - - reset_rx_filter(); - - rx_FFTprocess(buf, len); - - if (!clrcount--) clear_syncscope(); - - display_metric(metric); - - if ( (false || progStatus.show_channels ) - && !bHighSpeed && !bHistory ) - viewcw.rx_process(buf, len); - - cwprocessing = false; - - return 0; -} - -// ---------------------------------------------------------------------- - -// Compare two timestamps, and return the difference between them in usecs. - -inline int cw::usec_diff(unsigned int earlier, unsigned int later) -{ - return (earlier >= later) ? 0 : (later - earlier); -} - - -//======================================================================= -// handle_event() -// high level cw decoder... gets called with keyup, keydown, reset and -// query commands. -// Keyup/down influences decoding logic. -// Reset starts everything out fresh. -// The query command returns CW_SUCCESS and the character that has -// been decoded (may be '*',' ' or [a-z,0-9] or a few others) -// If there is no data ready, CW_ERROR is returned. -//======================================================================= - -int cw::handle_event(int cw_event, std::string &sc) -{ - static int space_sent = true; // for word space logic - static int last_element = 0; // length of last dot/dash - int element_usec; // Time difference in usecs - - switch (cw_event) { - case CW_RESET_EVENT: - sync_parameters(); - cw_receive_state = RS_IDLE; - cw_rr_current = 0; // reset decoding pointer - cw_ptr = 0; - memset(cw_buffer, 0, sizeof(cw_buffer)); - smpl_ctr = 0; // reset audio sample counter - rx_rep_buf.clear(); - break; - case CW_KEYDOWN_EVENT: -// A receive tone start can only happen while we -// are idle, or in the middle of a character. - if (cw_receive_state == RS_IN_TONE) - return CW_ERROR; -// first tone in idle state reset audio sample counter - if (cw_receive_state == RS_IDLE) { - smpl_ctr = 0; - rx_rep_buf.clear(); - cw_rr_current = 0; - cw_ptr = 0; - } -// save the timestamp - cw_rr_start_timestamp = smpl_ctr; -// Set state to indicate we are inside a tone. - old_cw_receive_state = cw_receive_state; - cw_receive_state = RS_IN_TONE; - return CW_ERROR; - break; - case CW_KEYUP_EVENT: -// The receive state is expected to be inside a tone. - if (cw_receive_state != RS_IN_TONE) - return CW_ERROR; -// Save the current timestamp - cw_rr_end_timestamp = smpl_ctr; - element_usec = usec_diff(cw_rr_start_timestamp, cw_rr_end_timestamp); - -// make sure our timing values are up to date - sync_parameters(); -// If the tone length is shorter than any noise cancelling -// threshold that has been set, then ignore this tone. - if (cw_noise_spike_threshold > 0 - && element_usec < cw_noise_spike_threshold) { - cw_receive_state = RS_IDLE; - return CW_ERROR; - } - -// Set up to track speed on dot-dash or dash-dot pairs for this test to work, we need a dot dash pair or a -// dash dot pair to validate timing from and force the speed tracking in the right direction. This method -// is fundamentally different than the method in the unix cw project. Great ideas come from staring at the -// screen long enough!. Its kind of simple really ... when you have no idea how fast or slow the cw is... -// the only way to get a threshold is by having both code elements and setting the threshold between them -// knowing that one is supposed to be 3 times longer than the other. with straight key code... this gets -// quite variable, but with most faster cw sent with electronic keyers, this is one relationship that is -// quite reliable. Lawrence Glaister (ve7it@shaw.ca) - if (last_element > 0) { -// check for dot dash sequence (current should be 3 x last) - if ((element_usec > 2 * last_element) && - (element_usec < 4 * last_element)) { - update_tracking(last_element, element_usec); - } -// check for dash dot sequence (last should be 3 x current) - if ((last_element > 2 * element_usec) && - (last_element < 4 * element_usec)) { - update_tracking(element_usec, last_element); - } - } - last_element = element_usec; -// ok... do we have a dit or a dah? -// a dot is anything shorter than 2 dot times - if (element_usec <= two_dots) { - rx_rep_buf += CW_DOT_REPRESENTATION; - // printf("%d dit ", last_element/1000); // print dot length - cw_buffer[cw_ptr++] = (float)last_element; - } else { -// a dash is anything longer than 2 dot times - rx_rep_buf += CW_DASH_REPRESENTATION; - cw_buffer[cw_ptr++] = (float)last_element; - } -// We just added a representation to the receive buffer. -// If it's full, then reset everything as it probably noise - if (rx_rep_buf.length() > MAX_MORSE_ELEMENTS) { - cw_receive_state = RS_IDLE; - cw_rr_current = 0; // reset decoding pointer - cw_ptr = 0; - smpl_ctr = 0; // reset audio sample counter - return CW_ERROR; - } else { -// zero terminate representation -// rx_rep_buf.clear(); - cw_buffer[cw_ptr] = 0.0; - } -// All is well. Move to the more normal after-tone state. - cw_receive_state = RS_AFTER_TONE; - return CW_ERROR; - break; - case CW_QUERY_EVENT: -// this should be called quite often (faster than inter-character gap) It looks after timing -// key up intervals and determining when a character, a word space, or an error char '*' should be returned. -// CW_SUCCESS is returned when there is a printable character. Nothing to do if we are in a tone - if (cw_receive_state == RS_IN_TONE) - return CW_ERROR; -// compute length of silence so far - sync_parameters(); - element_usec = usec_diff(cw_rr_end_timestamp, smpl_ctr); -// SHORT time since keyup... nothing to do yet - if (element_usec < (2 * cw_receive_dot_length)) - return CW_ERROR; -// MEDIUM time since keyup... check for character space -// one shot through this code via receive state logic -// FARNSWOTH MOD HERE --> - if (element_usec >= (2 * cw_receive_dot_length) && - element_usec <= (4 * cw_receive_dot_length) && - cw_receive_state == RS_AFTER_TONE) { -// Look up the representation - sc = morse->rx_lookup(rx_rep_buf); - if (sc.empty()) { -// invalid decode... let user see error - sc = (progdefaults.CW_noise == '*' ? "*" : - progdefaults.CW_noise == '_' ? "_" : - progdefaults.CW_noise == ' ' ? " " : ""); - - } - rx_rep_buf.clear(); - cw_receive_state = RS_IDLE; - cw_rr_current = 0; // reset decoding pointer - space_sent = false; - cw_ptr = 0; - - return CW_SUCCESS; - } -// LONG time since keyup... check for a word space -// FARNSWOTH MOD HERE --> - if ((element_usec > (4 * cw_receive_dot_length)) && !space_sent) { - sc = " "; - space_sent = true; - return CW_SUCCESS; - } -// should never get here... catch all - return CW_ERROR; - break; - } -// should never get here... catch all - return CW_ERROR; -} - -//=========================================================================== -// cw transmit routines -// Define the amplitude envelop for key down events (32 samples long) -// this is 1/2 cycle of a raised cosine -//=========================================================================== - -double keyshape[CWKNUM]; -double QSKkeyshape[CWKNUM]; - -void cw::create_edges() -{ - for (int i = 0; i < CWKNUM; i++) keyshape[i] = 1.0; - - switch (QSKshape) { - case 1: // blackman - knum = (int)(risetime * CW_SAMPLERATE / 1000); - if (knum >= symbollen) knum = symbollen; - for (int i = 0; i < knum; i++) - keyshape[i] = (0.42 - 0.50 * cos(M_PI * i/ knum) + 0.08 * cos(2 * M_PI * i / knum)); - break; - case 0: // hanning - default: - knum = (int)(risetime * CW_SAMPLERATE / 1000); - if (knum >= symbollen) knum = symbollen; - for (int i = 0; i < knum; i++) - keyshape[i] = 0.5 * (1.0 - cos (M_PI * i / knum)); - } - - for (int i = 0; i < CWKNUM; i++) QSKkeyshape[i] = 1.0; - - switch (QSKshape) { - case 1: // blackman - qnum = (int)(progdefaults.QSKrisetime * CW_SAMPLERATE / 1000); - if (qnum >= symbollen) qnum = symbollen; - for (int i = 0; i < qnum; i++) - QSKkeyshape[i] = (0.42 - 0.50 * cos(M_PI * i/ qnum) + 0.08 * cos(2 * M_PI * i / qnum)); - break; - case 0: // hanning - default: - qnum = (int)(progdefaults.QSKrisetime * CW_SAMPLERATE / 1000); - if (qnum >= symbollen) qnum = symbollen; - for (int i = 0; i < qnum; i++) - QSKkeyshape[i] = 0.5 * (1.0 - cos (M_PI * i / qnum)); - } -} - -inline double cw::nco(double freq) -{ - phaseacc += 2.0 * M_PI * freq / samplerate; - if (phaseacc > TWOPI) phaseacc -= TWOPI; - return sin(phaseacc); -} - -inline double cw::qsknco() -{ - double amp; - amp = sin(qskphase); - qskphase += TWOPI * progdefaults.QSKfrequency / samplerate; - if (qskphase > TWOPI) qskphase -= TWOPI; - return amp; -} - -//===================================================================== -// send_symbol() -// Sends a part of a morse character (one dot duration) of either -// sound at the correct freq or silence. Rise and fall time is controlled -// with a raised cosine shape. -// -// Left channel contains the shaped A2 CW waveform -// Right channel contains a square wave signal that is used -// to trigger a qsk switch. Right channel has pre and post timings for -// proper switching of the qsk switch before and after the A2 element. -// If the Pre + Post timing exceeds the interelement spacing then the -// Pre and / or Post is only applied at the beginning and end of the -// character. -//======================================================================= - -bool first_char = true; - -enum {START, FIRST, MID, LAST, SPACE}; - -void cw::send_symbol(int bit, int len, int state) -{ - double qsk_amp = progdefaults.QSK ? progdefaults.QSKamp : 0.0; - - sync_transmit_parameters(); - acc_symbols += len; - - memset(outbuf, 0, OUTBUFSIZE*sizeof(*outbuf)); - memset(qskbuf, 0, OUTBUFSIZE*sizeof(*qskbuf)); - - if (bit == 1) { // keydown - tx_frequency = get_txfreq(); - if (CW_KEYLINE_isopen || - progdefaults.CW_KEYLINE_on_cat_port || - progdefaults.CW_KEYLINE_on_ptt_port) - tx_frequency = progdefaults.CWsweetspot; - for (int n = 0; n < len; n++) { - outbuf[n] = nco(tx_frequency); - if (n < knum) outbuf[n] *= keyshape[n]; - if (len - n < knum) outbuf[n] *= keyshape[len - n]; - qskbuf[n] = qsk_amp * qsknco(); - } - } else { // keyup - for (int n = 0; n < len; n++) { - outbuf[n] = 0; - if (progdefaults.QSK) { - qskbuf[n] = 0; - if (state == START || state == FIRST) { - qskbuf[n] = 0; - if (n > len - kpre) { - qskbuf[n] = qsk_amp * qsknco(); - if (n < len - kpre + qnum) - qskbuf[n] *= QSKkeyshape[n - (len - kpre)]; - } - } else if (state == MID) { - qskbuf[n] = qsk_amp * qsknco(); - if (len > kpre + kpost) { - if (n < kpost) - qskbuf[n] *= QSKkeyshape[kpost - n]; - else if (n > len - kpre) - qskbuf[n] *= QSKkeyshape[n - (len - kpre)]; - else qskbuf[n] = 0; - } - } else if (state == LAST) { - qskbuf[n] = qsk_amp * qsknco(); - if (n > kpost - qnum) - qskbuf[n] *= QSKkeyshape[kpost - n]; - if (n >= kpost) qskbuf[n] = 0; - } else { // state == SPACE - qskbuf[n] = 0; - } - } - } - } - - if (progdefaults.QSK) - ModulateStereo(outbuf, qskbuf, len); - else - ModulateXmtr(outbuf, len); - -} - -//===================================================================== -// send_ch() -// sends a morse character and the space afterwards -//======================================================================= - -void cw::send_ch(int ch) -{ - std::string code; - - float kfactor = CW_SAMPLERATE / 1000.0; - float tc = 1200.0 / progdefaults.CWspeed; - float ta = 0.0; - float tch = 3 * tc, twd = 4 * tc; - - if (progdefaults.CWusefarnsworth && (progdefaults.CWspeed > progdefaults.CWfarnsworth)) { - ta = 60000.0 / progdefaults.CWfarnsworth - 37200.0 / progdefaults.CWspeed; - tch = 3 * ta / 19; - twd = 4 * ta / 19; - } - tc *= kfactor; - tch *= kfactor; - twd *= kfactor; - - sync_parameters(); - - if (progdefaults.CWpre < progdefaults.QSKrisetime) - kpre = progdefaults.QSKrisetime * kfactor; - else - kpre = progdefaults.CWpre * kfactor; - - if (progdefaults.CWpost < progdefaults.QSKrisetime) - kpost = progdefaults.QSKrisetime * kfactor; - else - kpost = progdefaults.CWpost * kfactor; - - if ((ch == ' ') || (ch == '\n')) { - send_symbol(0, - twd, - SPACE); - rx_text_buffer += (progdefaults.rx_lowercase ? tolower(ch) : ch); - return; - } - - code = morse->tx_lookup(ch); - if (!code.length()) { - return; - } - - float w = (progdefaults.CWdash2dot + 1) / (progdefaults.CWdash2dot -1); - - int elements = code.length(); - - if (kpre) - send_symbol( - 0, - (first_char ? kpre : - (kpre < 3 * tc - kpost) ? kpre : - 3 * tc ), - (first_char ? START : FIRST)); - - for (int n = 0; n < elements; n++) { - send_symbol(1, - (code[n] == '-' ? (w + 1) : (w - 1)) * symbollen, - MID); - send_symbol(0, - ((n < elements - 1) ? tc : - (kpost + kpre < 3 * tc) ? tch - kpre: - tch), - (n < elements - 1 ? MID : LAST) ); - } - - if (ch != -1) { - std::string prtstr = morse->tx_print(); - for (size_t n = 0; n < prtstr.length(); n++) - rx_text_buffer += prtstr[n]; - } -} - -//===================================================================== -// cw_txprocess() -// Read characters from screen and send them out the sound card. -// This is called repeatedly from a thread during tx. -//======================================================================= -int cw::tx_process() -{ - int c = get_tx_char(); - - if (c == GET_TX_CHAR_NODATA) { - if (stopflag) { - stopflag = false; - rx_text_buffer += std::string(1, '\n'); - first_char = true; - return -1; - } - // Fl::awake removed for Android; - MilliSleep(50); - return 0; - } - - if (progdefaults.use_FLRIGkeying) { - if (c == GET_TX_CHAR_ETX || stopflag) { - stopflag = false; - rx_text_buffer += std::string(1, '\n'); - return -1; - } - flrig_cwio_send(c); - rx_text_buffer += std::string(1, c); - return 0; - } - - if (progStatus.WK_online) { - if (c == GET_TX_CHAR_ETX || stopflag) { - stopflag = false; - rx_text_buffer += std::string(1, '\n'); - return -1; - } - if (WK_send_char(c)) { - rx_text_buffer += std::string(1, '\n'); - return -1; // WinKeyer problem - } - return 0; - } - - if (use_nanoIO) { - if (c == GET_TX_CHAR_ETX || stopflag) { - stopflag = false; - rx_text_buffer += std::string(1, '\n'); - return -1; - } - nano_send_char(c); - rx_text_buffer += std::string(1, c); - return 0; - } - - if (progdefaults.use_ELCTkeying || progdefaults.use_KNWDkeying) { - if (c == GET_TX_CHAR_ETX || stopflag) { - stopflag = false; - rx_text_buffer += std::string(1, '\n'); - return -1; - } - KYkeyer_send_char(c); - rx_text_buffer += std::string(1, c); - return 0; - } - - if (progdefaults.use_ICOMkeying) { - if (c == GET_TX_CHAR_ETX || stopflag) { - stopflag = false; - rx_text_buffer += std::string(1, '\n'); - return -1; - } - ICOMkeyer_send_char(c); - rx_text_buffer += std::string(1, c); - return 0; - } - - if (progdefaults.use_YAESUkeying) { - if (c == GET_TX_CHAR_ETX || stopflag) { - stopflag = false; - rx_text_buffer += std::string(1, '\n'); - return -1; - } - FTkeyer_send_char(c); - rx_text_buffer += std::string(1, c); - return 0; - } - - if (c == GET_TX_CHAR_ETX || stopflag) { - stopflag = false; - rx_text_buffer += std::string(1, '\n'); - first_char = true; - return -1; - } - - acc_symbols = 0; - - if (CW_KEYLINE_isopen || - progdefaults.CW_KEYLINE_on_cat_port || - progdefaults.CW_KEYLINE_on_ptt_port) - send_CW(c); -// else { - send_ch(c); - first_char = false; -// } - char_samples = acc_symbols; - - return 0; -} - -void cw::incWPM() -{ - - if (usedefaultWPM) return; - if (progdefaults.CWspeed < progdefaults.CWupperlimit) { - progdefaults.CWspeed++; - sync_parameters(); - set_CWwpm(); - update_Status(); - } -} - -void cw::decWPM() -{ - - if (usedefaultWPM) return; - if (progdefaults.CWspeed > progdefaults.CWlowerlimit) { - progdefaults.CWspeed--; - set_CWwpm(); - sync_parameters(); - update_Status(); - } -} - -void cw::toggleWPM() -{ - usedefaultWPM = !usedefaultWPM; - if (usedefaultWPM) { - wpm = progdefaults.CWspeed; - progdefaults.CWspeed = progdefaults.defCWspeed; - } else { - progdefaults.CWspeed = wpm; - } - sync_parameters(); - update_Status(); -} - -// --------------------------------------------------------------------- -// CW output on DTR/RTS signal lines -//---------------------------------------------------------------------- - -Cserial CW_KEYLINE_serial; -bool CW_KEYLINE_isopen = false; - -int open_CW_KEYLINE() -{ - CW_KEYLINE_serial.Device(progdefaults.CW_KEYLINE_serial_port_name); - CW_KEYLINE_serial.Baud(progdefaults.BaudRate(9)); - CW_KEYLINE_serial.RTS(false); - CW_KEYLINE_serial.DTR(false); - CW_KEYLINE_serial.RTSptt(false); - CW_KEYLINE_serial.DTRptt(false); - CW_KEYLINE_serial.RestoreTIO(true); - CW_KEYLINE_serial.RTSCTS(false); - CW_KEYLINE_serial.Stopbits(1); - - LOG_DEBUG("\n\ -CW Keyline Serial port parameters:\n\ -device : %s\n\ -baudrate : %d\n\ -stopbits : %d\n\ -initial rts: %+d\n\ -initial dtr: %+d\n\ -restore tio: %c\n\ -flowcontrol: %c\n", - CW_KEYLINE_serial.Device().c_str(), - CW_KEYLINE_serial.Baud(), - CW_KEYLINE_serial.Stopbits(), - (CW_KEYLINE_serial.RTS() ? +12 : -12), - (CW_KEYLINE_serial.DTR() ? +12 : -12), - (CW_KEYLINE_serial.RestoreTIO() ? 'T' : 'F'), - (CW_KEYLINE_serial.RTSCTS() ? 'T' : 'F') - ); - - if (CW_KEYLINE_serial.OpenPort() == false) { - LOG_ERROR("Cannot open serial port %s", CW_KEYLINE_serial.Device().c_str()); - CW_KEYLINE_isopen = false; - return 0; - } - CW_KEYLINE_isopen = true; - return 1; -} - -void close_CW_KEYLINE() -{ - CW_KEYLINE_serial.ClosePort(); - CW_KEYLINE_isopen = false; -} - -//---------------------------------------------------------------------- -#include - -static pthread_t cwio_pthread; -static pthread_cond_t cwio_cond; -static pthread_mutex_t cwio_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t fifo_mutex = PTHREAD_MUTEX_INITIALIZER; -pthread_mutex_t cwio_ptt_mutex = PTHREAD_MUTEX_INITIALIZER; - -static bool cwio_thread_running = false; -static bool cwio_terminate_flag = false; -static bool cwio_calibrate_flag = false; - -//---------------------------------------------------------------------- - -static int cwio_ch; -static cMorse *cwio_morse = 0; -static std::queue fifo; -static std::string cwio_prosigns; - -//---------------------------------------------------------------------- -// CW output using flrig cwio calls -//---------------------------------------------------------------------- -static char lastcwiochar = 0; -void flrig_cwio_send(char c) -{ - if (cwio_morse == 0) { - cwio_morse = new cMorse; - cwio_morse->init(); - } - -// if (c == '[') { -// flrig_cwio_ptt(1); -// return; -// } -// if (c == ']') { -// flrig_cwio_ptt(0); -// return; -// } - - std::string s = " "; - s[0] = c; - flrig_cwio_send_text(s); - if (c == '[' || c == ']') - return; - - int tc = 1200 / progdefaults.CWspeed; - if (progdefaults.CWusefarnsworth && (progdefaults.CWspeed > progdefaults.CWfarnsworth)) - tc = 1200 / progdefaults.CWfarnsworth; - - if (c == ' ') { - if (lastcwiochar == ' ') - tc *= 7; - else - tc *= 5; - } else - tc *= (cwio_morse->tx_length(c)); - lastcwiochar = c; - MilliSleep(tc); -} - -//---------------------------------------------------------------------- - -void cwio_key(int on) -{ - if (CW_KEYLINE_isopen || - progdefaults.CW_KEYLINE_on_cat_port || - progdefaults.CW_KEYLINE_on_ptt_port) { - Cserial *ser = &CW_KEYLINE_serial; - if (progdefaults.CW_KEYLINE_on_cat_port) - ser = &rigio; - else if (progdefaults.CW_KEYLINE_on_ptt_port) - ser = &push2talk->serPort; - switch (progdefaults.CW_KEYLINE) { - case 0: break; - case 1: ser->SetRTS(on); break; - case 2: ser->SetDTR(on); break; - } - } -} - -void cwio_ptt(int on) -{ - if (CW_KEYLINE_isopen || - progdefaults.CW_KEYLINE_on_cat_port || - progdefaults.CW_KEYLINE_on_ptt_port) { - Cserial *ser = &CW_KEYLINE_serial; - if (progdefaults.CW_KEYLINE_on_cat_port) - ser = &rigio; - else if (progdefaults.CW_KEYLINE_on_ptt_port) - ser = &push2talk->serPort; - switch (progdefaults.PTT_KEYLINE) { - case 0: break; - case 1: ser->SetRTS(on); break; - case 2: ser->SetDTR(on); break; - } - } -} - -/* -#define cwio_bit(bit, len) {\ -switch (progdefaults.CW_KEYLINE) {\ -case 0: break;\ -case 1: ser->SetRTS(bit); break;\ -case 2: ser->SetDTR(bit); break;\ -}\ -MilliSleep(len);} -*/ - -// return accurate time of day in secs - -double cwio_now() -{ - static struct timespec tp; - -#if 0 // HAVE_CLOCK_GETTIME disabled for Android - clock_gettime(CLOCK_MONOTONIC, &tp); -// return 1000.0 * tp.tv_sec + tp.tv_nsec * 1e-6; -#elif defined(__WIN32__) - DWORD msec = GetTickCount(); - return 1.0 * msec; - tp.tv_sec = msec / 1000; - tp.tv_nsec = (msec % 1000) * 1000000; -#elif defined(__APPLE__) - static mach_timebase_info_data_t info = { 0, 0 }; - if (unlikely(info.denom == 0)) - mach_timebase_info(&info); - uint64_t t = mach_absolute_time() * info.numer / info.denom; -// return t * 1e-6; - tp.tv_sec = t / 1000000000; - tp.tv_nsec = t % 1000000000; -#endif - return 1.0 * tp.tv_sec + tp.tv_nsec * 1e-9; - -} - -// set DTR/RTS to bit value for msecs duration - -//#define CW_TTEST -#ifdef CW_TTEST -static FILE *cwio_test = 0; -#endif - -void cwio_bit(int bit, double msecs) -{ -std::cout << bit << " : " << msecs << std::endl; -#ifdef CW_TTEST - if (!cwio_test) cwio_test = fopen("cwio_test.txt", "a"); -#endif - static double secs; - static struct timespec tv = { 0, 1000000L}; - static double end1 = 0; - static double end2 = 0; - static double t1 = 0; -#ifdef CW_TTEST - static double t2 = 0; -#endif - static double t3 = 0; - static double t4 = 0; - int loop1 = 0; - int loop2 = 0; - int n1 = msecs * 1e3; - - secs = msecs * 1e-3; - -#ifdef __WIN32__ - timeBeginPeriod(1); -#endif - - t1 = cwio_now(); - - end2 = t1 + secs - 0.00001; - - cwio_key(bit); - -#ifdef CW_TTEST - t2 = t3 = cwio_now(); -#else - t3 = cwio_now(); -#endif - end1 = end2 - 0.005; - - while (t3 < end1 && (++loop1 < n1)) { - nanosleep(&tv, NULL); - t3 = cwio_now(); - } - - t4 = t3; - while (t4 <= end2) { - loop2++; - t4 = cwio_now(); - } - -#ifdef __WIN32__ - timeEndPeriod(1); -#endif - -#ifdef CW_TTEST - if (cwio_test) - fprintf(cwio_test, "%d, %d, %d, %6f, %6f, %6f, %6f, %6f, %6f, %6f\n", - bit, loop1, loop2, - secs * 1e3, - (t2 - t1)*1e3, - (t3 - t1)*1e3, - (t3 - end1) * 1e3, - (t4 - t1)*1e3, - (t4 - end2) * 1e3, - (t4 - t1 - secs)*1e3); -#endif -} - -void send_cwio(int c) -{ - if (c == GET_TX_CHAR_NODATA || c == 0x0d) { - return; - } - - float tc = 1200.0 / progdefaults.CWspeed; - if (tc <= 0) tc = 1; - float ta = 0.0; - float tch = 3 * tc, twd = 4 * tc; - -// Cserial *ser = &CW_KEYLINE_serial; -// if (progdefaults.CW_KEYLINE_on_cat_port) -// ser = &rigio; -// else if (progdefaults.CW_KEYLINE_on_ptt_port) -// ser = &push2talk->serPort; - - if (progdefaults.CWusefarnsworth && (progdefaults.CWspeed > progdefaults.CWfarnsworth)) { - ta = 60000.0 / progdefaults.CWfarnsworth - 37200 / progdefaults.CWspeed; - tch = 3 * ta / 19; - twd = 4 * ta / 19; - } - - if (c == 0x0a) c = ' '; - - if (c == ' ') { - cwio_bit(0, twd); - return; - } - - std::string code; - code = cwio_morse->tx_lookup(c); - if (!code.length()) { - return; - } - - double xcvr_corr = progdefaults.CWkeycomp; - if (xcvr_corr < -tc / 2) xcvr_corr = - tc / 2; - else if (xcvr_corr > tc / 2) xcvr_corr = tc / 2; - - guard_lock lk(&cwio_ptt_mutex); - - for (size_t n = 0; n < code.length(); n++) { - if (code[n] == '.') { - cwio_bit(1, tc + xcvr_corr); - } else { - cwio_bit(1, 3*tc + xcvr_corr); - } - if (n < code.length() -1) { - cwio_bit(0, tc - xcvr_corr); - } else { - cwio_bit(0, tch - xcvr_corr); - } - } - -} - -unsigned long start_time = 0L; -unsigned long end_time = 0L; -int testwpm = 20; - -void cwio_calibrate_finished(void *) -{ - double ratio = 60000.0 / (end_time - start_time); - btn_cw_dtr_calibrate->value(0); - - static char result[100]; - snprintf(result, sizeof(result), "Time: %0.4f secs, %%error: %0.2f", - (end_time - start_time) / 1000.0, - 100.0 * (1-ratio)); - LOG_INFO("\n%s\n", result); - cwio_test_result->value(result); - cwio_test_result->redraw(); -} - -void cwio_calibrate() -{ - std::string paris = "PARIS "; - bool farnsworth = progdefaults.CWusefarnsworth; - progdefaults.CWusefarnsworth = false; - - guard_lock lk(&fifo_mutex); - - start_time = zmsec(); - for (int i = 0; i < progdefaults.CWspeed; i++) - for (size_t n = 0; n < paris.length(); n++) - send_cwio(paris[n]); - end_time = zmsec(); - - progdefaults.CWusefarnsworth = farnsworth; - - // Fl::awake removed for Android; -} - -static void * cwio_loop(void *args) -{ - SET_THREAD_ID(CWIO_TID); - - cwio_thread_running = true; - cwio_terminate_flag = false; - - while(1) { - pthread_mutex_lock(&cwio_mutex); - pthread_cond_wait(&cwio_cond, &cwio_mutex); - pthread_mutex_unlock(&cwio_mutex); - - if (cwio_terminate_flag) - break; - if (cwio_calibrate_flag) { - cwio_calibrate(); - cwio_calibrate_flag = false; - } - while (!fifo.empty()) { - { - guard_lock lk(&fifo_mutex); - cwio_ch = fifo.front(); - fifo.pop(); - } - send_cwio(cwio_ch); - } - } - return (void *)0; -} - -void calibrate_cwio() -{ - if (!cwio_thread_running) - // start_cwio_thread() removed for Android - - if (cwio_morse == 0) { - cwio_morse = new cMorse; - cwio_morse->init(); - } - - cwio_calibrate_flag = true; - pthread_cond_signal(&cwio_cond); -} - -void stop_cwio_thread(void) -{ - if(!cwio_thread_running) return; - - cwio_terminate_flag = true; - pthread_cond_signal(&cwio_cond); - - MilliSleep(10); - - pthread_join(cwio_pthread, NULL); - - pthread_mutex_destroy(&cwio_mutex); - pthread_cond_destroy(&cwio_cond); - - memset((void *) &cwio_pthread, 0, sizeof(cwio_pthread)); - memset((void *) &cwio_mutex, 0, sizeof(cwio_mutex)); - - cwio_thread_running = false; - cwio_terminate_flag = false; - - delete cwio_morse; - cwio_morse = 0; -} - -void start_cwio_thread(void) -{ - if (cwio_thread_running) return; - - memset((void *) &cwio_pthread, 0, sizeof(cwio_pthread)); - memset((void *) &cwio_mutex, 0, sizeof(cwio_mutex)); - memset((void *) &cwio_cond, 0, sizeof(cwio_cond)); - - if(pthread_cond_init(&cwio_cond, NULL)) { - LOG_ERROR("Alert thread create fail (pthread_cond_init)"); - return; - } - - if(pthread_mutex_init(&cwio_mutex, NULL)) { - LOG_ERROR("AUDIO_ALERT thread create fail (pthread_mutex_init)"); - return; - } - - if (pthread_create(&cwio_pthread, NULL, cwio_loop, NULL) < 0) { - pthread_mutex_destroy(&cwio_mutex); - LOG_ERROR("AUDIO_ALERT thread create fail (pthread_create)"); - } - - LOG_DEBUG("started audio cwio thread"); - - MilliSleep(10); // Give the CPU time to set 'cwio_thread_running' -} - -void cw::send_CW(int c) -{ - if (!cwio_thread_running) - // start_cwio_thread() removed for Android - - if (cwio_morse == 0) { - cwio_morse = new cMorse; - cwio_morse->init(); - } - - if (cwio_prosigns != progdefaults.CW_prosigns) { - cwio_prosigns = progdefaults.CW_prosigns; - cwio_morse->init(); - } - - guard_lock lk(&fifo_mutex); - fifo.push(c); - - pthread_cond_signal(&cwio_cond); - -} - -unsigned long CAT_start_time = 0L; -unsigned long CAT_end_time = 0L; - -void CAT_keying_calibrate_finished(void *) -{ - out_CATkeying_compensation->value(progdefaults.CATkeying_compensation / 1000.0); - char info[1000]; - snprintf(info, sizeof(info), - "Speed test: %.0f wpm : %0.2f secs", - progdefaults.CWspeed, - progdefaults.CATkeying_compensation / 1000.0); - LOG_DEBUG("\n%s", info); -} - -static pthread_t CW_keying_pthread; -bool CW_CAT_thread_running = false; - -void *do_CAT_keying_calibrate(void *args) -{ - CW_CAT_thread_running = true; - -LOG_DEBUG("%s", "CAT keying calibrate thread running"); - - bool tempcwTrack = active_modem->get_cwTrack(); - progdefaults.CWtrack = false; - active_modem->set_cwTrack(false); -LOG_DEBUG("1"); - progdefaults.CWspeed = cntCW_WPM->value(); - active_modem->calWPM(progdefaults.CWspeed); - sldrCWxmtWPM->value(progdefaults.CWspeed); - cntr_nanoCW_WPM->value(progdefaults.CWspeed); -LOG_DEBUG("2"); - bool farnsworth = progdefaults.CWusefarnsworth; - progdefaults.CWusefarnsworth = false; - progdefaults.CATkeying_compensation = 0; -LOG_DEBUG("3"); - if (progStatus.WK_online) { - WK_set_wpm(); - WK_reset_timing(); - } else if (progdefaults.use_KNWDkeying || progdefaults.use_ELCTkeying) - set_KYkeyer(); - else if (progdefaults.use_ICOMkeying) - set_ICOMkeyer(); - else if (progdefaults.use_YAESUkeying) - set_FTkeyer(); -LOG_DEBUG("4"); - std::string paris = "PARIS "; - - CAT_start_time = zmsec(); -LOG_DEBUG("5"); - for (int i = 0; i < progdefaults.CWspeed; i++) { -LOG_DEBUG("6"); - for (size_t n = 0; n < paris.length(); n++) { -LOG_DEBUG("7"); - if (progdefaults.use_KNWDkeying || progdefaults.use_ELCTkeying) - KYkeyer_send_char(paris[n]); - else if (progdefaults.use_ICOMkeying) - ICOMkeyer_send_char(paris[n]); - else if (progdefaults.use_YAESUkeying) - FTkeyer_send_char(paris[n]); - else if (progStatus.WK_online) { - WK_send_char(paris[n]); - } - // Fl::awake removed for Android; - } - } - CAT_end_time = zmsec(); - - progdefaults.CATkeying_compensation = (CAT_end_time - CAT_start_time - 60000); - - if (progStatus.WK_online) - WK_set_comp(); - - progdefaults.CWusefarnsworth = farnsworth; - - // Fl::awake removed for Android; - CW_CAT_thread_running = false; - - progdefaults.CWtrack = tempcwTrack; - active_modem->set_cwTrack(tempcwTrack); - -LOG_DEBUG("%s", "exiting calibration thread"); - - return NULL; -} - -void CAT_keying_calibrate() -{ - if (CW_CAT_thread_running) return; - - if (pthread_create(&CW_keying_pthread, NULL, do_CAT_keying_calibrate, NULL) < 0) { - LOG_ERROR("CW CAT calibration thread create failed"); - return; - } - - LOG_DEBUG("started CW CAT calibration thread"); - - MilliSleep(10); - -} - -void CAT_keying_test_finished(void *) -{ - int comp = (CAT_end_time - CAT_start_time - 60000); - out_CATkeying_test_result->value(comp / 1000.0); -} - -void *do_CAT_keying_test(void *args) -{ - CW_CAT_thread_running = true; - - bool tempcwTrack = active_modem->get_cwTrack(); - progdefaults.CWtrack = false; - active_modem->set_cwTrack(false); - - progdefaults.CWspeed = cntCW_WPM->value(); - sldrCWxmtWPM->value(progdefaults.CWspeed); - cntr_nanoCW_WPM->value(progdefaults.CWspeed); - - progdefaults.CW_cal_speed = progdefaults.CWspeed; - - bool farnsworth = progdefaults.CWusefarnsworth; - progdefaults.CWusefarnsworth = false; - - if (progStatus.WK_online) { - WK_set_wpm(); - } else if (progdefaults.use_KNWDkeying || progdefaults.use_ELCTkeying) - set_KYkeyer(); - else if (progdefaults.use_ICOMkeying) - set_ICOMkeyer(); - else if (progdefaults.use_YAESUkeying) - set_FTkeyer(); - - std::string paris = "PARIS "; - - CAT_start_time = zmsec(); - for (int i = 0; i < progdefaults.CW_cal_speed; i++) { - for (size_t n = 0; n < paris.length(); n++) { - if (progStatus.WK_online) { - WK_send_char(paris[n]); - } - if (progdefaults.use_KNWDkeying || progdefaults.use_ELCTkeying) - KYkeyer_send_char(paris[n]); - else if (progdefaults.use_ICOMkeying) - ICOMkeyer_send_char(paris[n]); - else if (progdefaults.use_YAESUkeying) - FTkeyer_send_char(paris[n]); - // Fl::awake removed for Android; - } - } - CAT_end_time = zmsec(); - - progdefaults.CWusefarnsworth = farnsworth; - - // Fl::awake removed for Android; - CW_CAT_thread_running = false; - - progdefaults.CWtrack = tempcwTrack; - active_modem->set_cwTrack(tempcwTrack); - - return NULL; -} - -void CAT_keying_test() -{ - if (CW_CAT_thread_running) return; - - if (pthread_create(&CW_keying_pthread, NULL, do_CAT_keying_test, NULL) < 0) { - LOG_ERROR("CW CAT calibration thread create failed"); - return; - } - - LOG_DEBUG("started CW CAT calibration thread"); - - MilliSleep(10); - -} diff --git a/feature/cw/src/main/cpp/fldigi/cw.h b/feature/cw/src/main/cpp/fldigi/cw.h deleted file mode 100644 index 10a7b2f6..00000000 --- a/feature/cw/src/main/cpp/fldigi/cw.h +++ /dev/null @@ -1,197 +0,0 @@ -// ---------------------------------------------------------------------------- -// cw.h -- morse code modem (Android adaptation) -// Copyright (C) 2006-2009 Dave Freese, W1HKJ -// Adapted from fldigi/src/include/cw.h (GPL v3). -// ---------------------------------------------------------------------------- -#ifndef _CW_H -#define _CW_H - -#include -#include -#include - -#include "modem.h" -#include "filters.h" -#include "fftfilt.h" -#include "mbuffer.h" -#include "view_cw.h" - -#define CW_SAMPLERATE 8000 -#define CWMaxSymLen 4096 -#define MAX_MORSE_ELEMENTS 6 -#define CW_SUCCESS 0 -#define CW_ERROR -1 -#define ASC_NUL '\0' -#define ASC_SPACE ' ' -#define KWPM (12 * CW_SAMPLERATE / 10) -#define CWKNUM ((KWPM) / 10) -#define TONE_SILENT 0 -#define USECS_PER_SEC 1000000 -#define INITIAL_SEND_SPEED 18 -#define INITIAL_RECEIVE_SPEED 18 -#define INITIAL_THRESHOLD (((KWPM) / INITIAL_RECEIVE_SPEED) * 2) -#define INITIAL_NOISE_THRESHOLD (((KWPM) / CW_MAX_SPEED) / 2) -#define TRACKING_FILTER_SIZE 16 -#define MAX_PIPE_SIZE (22 * CW_SAMPLERATE * 12 / 800) -#define CW_MAX_SPEED 100 - -enum CW_RX_STATE { - RS_IDLE = 0, - RS_IN_TONE, - RS_AFTER_TONE -}; - -enum CW_EVENT { - CW_RESET_EVENT, - CW_KEYDOWN_EVENT, - CW_KEYUP_EVENT, - CW_QUERY_EVENT -}; - -class cw : public modem { -public: -#define CLRCOUNT 16 -#define DEC_RATIO 16 -#define WGT_SIZE 7 - - struct SOM_TABLE { - std::string rpr; - float wgt[WGT_SIZE]; - }; - -protected: - int symbollen; - int fsymlen; - double phaseacc; - double FFTphase; - double FFTvalue; - unsigned int smpl_ctr; - double agc_peak; - bool use_matched_filter; - double upper_threshold; - double lower_threshold; - fftfilt *cw_FFT_filter; - Cmovavg *bitfilter; - Cmovavg *trackingfilter; - int bitfilterlen; - CW_RX_STATE cw_receive_state; - CW_RX_STATE old_cw_receive_state; - CW_EVENT cw_event; - double pipe[MAX_PIPE_SIZE + 1]; - double clearpipe[MAX_PIPE_SIZE + 1]; - mbuffer scopedata; - int pipeptr; - int pipesize; - bool scope_clear; - - // Config (from progdefaults, replaced for Android) - int cw_speed; - int cw_bandwidth; - int cw_squelch; - int cw_send_speed; - int cw_receive_speed; - bool usedefaultWPM; - int cw_upper_limit; - int cw_lower_limit; - long int cw_noise_spike_threshold; - int cw_in_sync; - long int cw_send_dot_length; - long int cw_send_dash_length; - int lastsym; - double risetime; - int knum; - int qnum; - int QSKshape; - double qskbuf[OUTBUFSIZE]; - double qskphase; - bool firstelement; - bool lastelement; - double maxval; - long int cw_receive_dot_length; - long int cw_receive_dash_length; - std::string rx_rep_buf; - int cw_rr_current; - unsigned int cw_rr_start_timestamp; - unsigned int cw_rr_end_timestamp; - long int two_dots; - int in_replay; - double dot_tracking; - double dash_tracking; - - // Android additions - std::string rx_text_buffer; // decoded text for JNI retrieval - - inline double nco(double freq); - inline double qsknco(); - void update_syncscope(); - void clear_syncscope(); - void update_Status(); - void sync_parameters(); - void reset_rx_filter(); - int handle_event(int cw_event, std::string &sc); - inline int usec_diff(unsigned int earlier, unsigned int later); - void send_symbol(int symbol, int len, int state); - void send_ch(int c); - bool tables_init(); - unsigned int tokenize_representation(char *representation); - void update_tracking(int dot, int dash); - - static const SOM_TABLE som_table[]; - float cw_buffer[512]; - int cw_ptr; - int clrcount; - double lowerwpm; - double upperwpm; - int synchscope; - double noise_floor; - double sig_avg; - double siglevel; - bool use_paren; - std::string prosigns; - cmplx mixer(cmplx in); - - int nusymbollen; - int nufsymlen; - int kpre; - int kpost; - double wpm; - double fwpm; - double cal_wpm; - void create_edges(); - void sync_transmit_parameters(); - void flush_audio(); - void send_CW(int); - view_cw viewcw; - -public: - cw(); - ~cw(); - void init(); - void rx_init(); - void tx_init(); - void restart() {} - - int rx_process(const double *buf, int len); - void rx_FFTprocess(const double *buf, int len); - void rx_FIRprocess(const double *buf, int len); - void decode_stream(double); - - int tx_process(); - void incWPM(); - void decWPM(); - void toggleWPM(); - double calWPM() { return cal_wpm; } - void calWPM(double val) { cal_wpm = val; } - - int normalize(float *v, int n, int twodots); - std::string find_winner(float *inbuf, int twodots); - - // Android: get and clear decoded text buffer - std::string get_rx_text() { - std::string result = rx_text_buffer; - rx_text_buffer.clear(); - return result; - } -}; - -#endif \ No newline at end of file diff --git a/feature/cw/src/main/cpp/fldigi/fftfilt.cxx b/feature/cw/src/main/cpp/fldigi/fftfilt.cxx deleted file mode 100644 index 0cb46bb3..00000000 --- a/feature/cw/src/main/cpp/fldigi/fftfilt.cxx +++ /dev/null @@ -1,315 +0,0 @@ -// ---------------------------------------------------------------------------- -// fftfilt.cxx -- Fast convolution Overlap-Add filter -// -// Filter implemented using overlap-add FFT convolution method -// h(t) characterized by Windowed-Sinc impulse response -// -// Reference: -// "The Scientist and Engineer's Guide to Digital Signal Processing" -// by Dr. Steven W. Smith, http://www.dspguide.com -// Chapters 16, 18 and 21 -// -// Copyright (C) 2006-2008 Dave Freese, W1HKJ -// -// This file is part of fldigi. -// -// Fldigi 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. -// -// Fldigi 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 fldigi. If not, see . -// ---------------------------------------------------------------------------- - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "misc.h" -#include "fftfilt.h" - -//------------------------------------------------------------------------------ -// initialize the filter -// create forward and reverse FFTs -//------------------------------------------------------------------------------ - -// probably only need a single instance of g_fft !! -// use for both forward and reverse - -void fftfilt::clear_filter() -{ - for (int i = 0; i < flen; i++) { - filter[i] = 0; - timedata[i] = 0; - freqdata[i] = 0; - output[i] = 0; - ht[i] = 0; - } - for (int i = 0; i < flen2; i++) - ovlbuf[i] = 0; - inptr = 0; -} - -void fftfilt::init_filter() -{ - flen2 = flen >> 1; - fft = new g_fft(flen); - - filter = new cmplx[flen]; - timedata = new cmplx[flen]; - freqdata = new cmplx[flen]; - output = new cmplx[flen]; - ovlbuf = new cmplx[flen2]; - ht = new cmplx[flen]; -} - -// number of samples needed to completely flush the filter -int fftfilt::flush_size() -{ - return flen - inptr; -} - -//------------------------------------------------------------------------------ -// fft filter -// f1 < f2 ==> band pass filter -// f1 > f2 ==> band reject filter -// f1 == 0 ==> low pass filter -// f2 == 0 ==> high pass filter -//------------------------------------------------------------------------------ -fftfilt::fftfilt(double f1, double f2, int len) -{ - flen = len; - init_filter(); - create_filter(f1, f2); -} - -//------------------------------------------------------------------------------ -// low pass filter -//------------------------------------------------------------------------------ -fftfilt::fftfilt(double f, int len) -{ - flen = len; - init_filter(); - create_lpf(f); -} - -fftfilt::~fftfilt() -{ - if (fft) delete fft; - - if (filter) delete [] filter; - if (timedata) delete [] timedata; - if (freqdata) delete [] freqdata; - if (output) delete [] output; - if (ovlbuf) delete [] ovlbuf; - if (ht) delete [] ht; -} - -void fftfilt::create_filter(double f1, double f2) -{ - clear_filter(); -// initialize the filter to zero - for (int i = 0; i < flen; i++) ht[i] = 0; - -// create the filter shape coefficients by fft -// filter values initialized to the ht response h(t) - bool b_lowpass, b_highpass;//, window; - b_lowpass = (f2 != 0); - b_highpass = (f1 != 0); - - for (int i = 0; i < flen2; i++) { - ht[i] = 0; -//combine lowpass / highpass -// lowpass @ f2 - if (b_lowpass) ht[i] += fsinc(f2, i, flen2); -// highighpass @ f1 - if (b_highpass) ht[i] -= fsinc(f1, i, flen2); - } -// highpass is delta[flen2/2] - h(t) - if (b_highpass && f2 < f1) ht[flen2 / 2] += 1; - - for (int i = 0; i < flen2; i++) - ht[i] *= _blackman(i, flen2); - -// this may change since green fft is in place fft - memcpy(filter, ht, flen * sizeof(cmplx)); - -// ht is flen complex points with imaginary all zero -// first half describes h(t), second half all zeros -// perform the cmplx forward fft to obtain H(w) -// filter is flen/2 complex values - - fft->ComplexFFT(filter); -// fft->transform(ht, filter); - -// normalize the output filter for unity gain - double scale = 0, mag; - for (int i = 0; i < flen2; i++) { - mag = abs(filter[i]); - if (mag > scale) scale = mag; - } - if (scale != 0) { - for (int i = 0; i < flen; i++) - filter[i] /= scale; - } - -// perform the reverse fft to obtain h(t) -// for testing -// uncomment to obtain filter characteristics -/* - cmplx *revht = new cmplx[flen]; - memcpy(revht, filter, flen * sizeof(cmplx)); - - fft->InverseComplexFFT(revht); - - std::fstream fspec; - fspec.open("fspec.csv", std::ios::out); - fspec << "i,imp.re,imp.im,filt.re,filt.im,filt.abs,revimp.re,revimp.im\n"; - for (int i = 0; i < flen2; i++) - fspec - << i << "," << ht[i].real() << "," << ht[i].imag() << "," - << filter[i].real() << "," << filter[i].imag() << "," - << abs(filter[i]) << "," - << revht[i].real() << "," << revht[i].imag() << "," - << std::endl; - fspec.close(); - delete [] revht; -*/ -// start output after 2 full passes are complete - pass = 1; -} - -/* - * Filter with fast convolution (overlap-add algorithm). - */ - -int fftfilt::run(const cmplx & in, cmplx **out) -{ -// collect flen/2 input samples - timedata[inptr++] = in; - - if (inptr < flen2) - return 0; - if (pass) --pass; // filter output is not stable until 2 passes - -// FFT transpose to the frequency domain - memcpy(freqdata, timedata, flen * sizeof(cmplx)); - fft->ComplexFFT(freqdata); - -// multiply with the filter shape - for (int i = 0; i < flen; i++) - freqdata[i] *= filter[i]; - -// transform back to time domain - fft->InverseComplexFFT(freqdata); - -// overlap and add -// save the second half for overlapping next inverse FFT - for (int i = 0; i < flen2; i++) { - output[i] = ovlbuf[i] + freqdata[i]; - ovlbuf[i] = freqdata[i+flen2]; - } - -// clear inbuf pointer - inptr = 0; - -// signal the caller there is flen/2 samples ready - if (pass) return 0; - - *out = output; - return flen2; -} - -//------------------------------------------------------------------------------ -// rtty filter -//------------------------------------------------------------------------------ - -//bool print_filter = true; // flag to inhibit printing multiple copies - -void fftfilt::rtty_filter(double f) -{ -// Raised cosine filter designed iaw Section 1.2.6 of -// Telecommunications Measurements, Analysis, and Instrumentation -// by Dr. Kamilo Feher / Engineers of Hewlett-Packard -// -// Frequency scaling factor determined hueristically by testing various values -// and measuring resulting decoder CER with input s/n = - 9 dB -// -// K CER -// 1.0 .0244 -// 1.1 .0117 -// 1.2 .0081 -// 1.3 .0062 -// 1.4 .0054 -// 1.5 .0062 -// 1.6 .0076 - - f *= 1.4; - - double dht; - for( int i = 0; i < flen2; ++i ) { - double x = (double)i/(double)(flen2); - -// raised cosine response (changed for -1.0...+1.0 times Nyquist-f -// instead of books versions ranging from -1..+1 times samplerate) - - dht = - x <= 0 ? 1.0 : - x > 2.0 * f ? 0.0 : - cos((M_PI * x) / (f * 4.0)); - - dht *= dht; // cos^2 - -// amplitude equalized nyquist-channel response - dht /= sinc(2.0 * i * f); - - filter[i] = - cmplx( dht*cos((double)i* - 0.5*M_PI), - dht*sin((double)i* - 0.5*M_PI) ); - - filter[(flen-i)%flen] = - cmplx( dht*cos((double)i*+0.5*M_PI), - dht*sin((double)i*+0.5*M_PI) ); - } - -// perform the reverse fft to obtain h(t) -// for testing -// uncomment to obtain filter characteristics -/* - cmplx *revht = new cmplx[flen]; - memcpy(revht, filter, flen * sizeof(cmplx)); - - fft->InverseComplexFFT(revht); - - std::fstream fspec; - fspec.open("rtty_filter.csv", std::ios::out); - fspec << "i,filt.re,filt.im,filt.abs,,revimp.re,revimp.im\n"; - for (int i = 0; i < flen; i++) - fspec - << i << "," - << filter[i].real() << "," << filter[i].imag() << "," << abs(filter[i]) - << ",," << revht[i].real() << "," << revht[i].imag() - << std::endl; - fspec.close(); - delete [] revht; -*/ -// start output after 2 full passes are complete - pass = 1; -} - diff --git a/feature/cw/src/main/cpp/fldigi/fftfilt.h b/feature/cw/src/main/cpp/fldigi/fftfilt.h deleted file mode 100644 index 9fc8f1a8..00000000 --- a/feature/cw/src/main/cpp/fldigi/fftfilt.h +++ /dev/null @@ -1,78 +0,0 @@ -// ---------------------------------------------------------------------------- -// Copyright (C) 2014 -// David Freese, W1HKJ -// -// This file is part of fldigi -// -// fldigi 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. -// -// fldigi 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 . -// ---------------------------------------------------------------------------- - -#ifndef _FFTFILT_H -#define _FFTFILT_H - -#include "complex.h" -#include "gfft.h" - -//---------------------------------------------------------------------- - -class fftfilt { -enum {NONE, BLACKMAN, HAMMING, HANNING}; - -protected: - int flen; - int flen2; - g_fft *fft; - g_fft *ift; - cmplx *ht; - cmplx *filter; - cmplx *timedata; - cmplx *freqdata; - cmplx *ovlbuf; - cmplx *output; - int inptr; - int pass; - int window; - - inline double fsinc(double fc, int i, int len) { - return (i == len/2) ? 2.0 * fc: - sin(2 * M_PI * fc * (i - len/2)) / (M_PI * (i - len/2)); - } - inline double _blackman(int i, int len) { - return (0.42 - - 0.50 * cos(2.0 * M_PI * i / len) + - 0.08 * cos(4.0 * M_PI * i / len)); - } - void init_filter(); - void clear_filter(); - -public: - fftfilt(double f1, double f2, int len); - fftfilt(double f, int len); - ~fftfilt(); -// f1 < f2 ==> bandpass -// f1 > f2 ==> band reject - void create_filter(double f1, double f2); - void create_lpf(double f) { - create_filter(0, f); - } - void create_hpf(double f) { - create_filter(f, 0); - } - void rtty_filter(double); - - int run(const cmplx& in, cmplx **out); - int flush_size(); -}; - -#endif diff --git a/feature/cw/src/main/cpp/fldigi/filters.cxx b/feature/cw/src/main/cpp/fldigi/filters.cxx deleted file mode 100644 index e038372f..00000000 --- a/feature/cw/src/main/cpp/fldigi/filters.cxx +++ /dev/null @@ -1,551 +0,0 @@ -// ---------------------------------------------------------------------------- -// -// filters.cxx -- Several Digital Filter classes used in fldigi -// -// Copyright (C) 2006-2008 Dave Freese, W1HKJ -// -// These filters are based on the gmfsk design and the design notes given in -// "Digital Signal Processing, A Practical Guid for Engineers and Scientists" -// by Steven W. Smith. -// -// This file is part of fldigi. -// -// Fldigi 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. -// -// Fldigi 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 fldigi. If not, see . -// ---------------------------------------------------------------------------- - -#include - -#include -#include -#include - -#include "filters.h" - -#include - - -//===================================================================== -// C_FIR_filter -// -// a class of Finite Impulse Response (FIR) filters with -// decimate in time capability -// -//===================================================================== - -C_FIR_filter::C_FIR_filter () { - pointer = counter = length = 0; - decimateratio = 1; - ifilter = qfilter = (double *)0; - ffreq = 0.0; -} - -C_FIR_filter::~C_FIR_filter() { - if (ifilter) delete [] ifilter; - if (qfilter) delete [] qfilter; -} - -void C_FIR_filter::init(int len, int dec, double *itaps, double *qtaps) { - length = len; - decimateratio = dec; - if (ifilter) { - delete [] ifilter; - ifilter = (double *)0; - } - if (qfilter) { - delete [] qfilter; - qfilter = (double *)0; - } - - for (int i = 0; i < FIRBufferLen; i++) - ibuffer[i] = qbuffer[i] = 0.0; - - if (itaps) { - ifilter = new double[len]; - for (int i = 0; i < len; i++) ifilter[i] = itaps[i]; - } - if (qtaps) { - qfilter = new double[len]; - for (int i = 0; i < len; i++) qfilter[i] = qtaps[i]; - } - - pointer = len; - counter = 0; -} - - -//===================================================================== -// Create a band pass FIR filter with 6 dB corner frequencies -// of 'f1' and 'f2'. (0 <= f1 < f2 <= 0.5) -//===================================================================== - -double * C_FIR_filter::bp_FIR(int len, int hilbert, double f1, double f2) -{ - double *fir; - double t, h, x; - - fir = new double[len]; - - for (int i = 0; i < len; i++) { - t = i - (len - 1.0) / 2.0; - h = i * (1.0 / (len - 1.0)); - - if (!hilbert) { - x = (2 * f2 * sinc(2 * f2 * t) - - 2 * f1 * sinc(2 * f1 * t)) * hamming(h); - } else { - x = (2 * f2 * cosc(2 * f2 * t) - - 2 * f1 * cosc(2 * f1 * t)) * hamming(h); -// The actual filter code assumes the impulse response -// is in time reversed order. This will be anti- -// symmetric so the minus sign handles that for us. - x = -x; - } - - fir[i] = x; - } - - return fir; -} - -//===================================================================== -// Filter will be a lowpass with -// length = len -// decimation = dec -// 0.5 frequency point = freq -//===================================================================== - -void C_FIR_filter::init_lowpass (int len, int dec, double freq) { - double *fi = bp_FIR(len, 0, 0.0, freq); - ffreq = freq; - init (len, dec, fi, fi); - delete [] fi; -} - -//===================================================================== -// Filter will be a bandpass with -// length = len -// decimation = dec -// 0.5 frequency points of f1 (low) and f2 (high) -//===================================================================== - -void C_FIR_filter::init_bandpass (int len, int dec, double f1, double f2) { - double *fi = bp_FIR (len, 0, f1, f2); - init (len, dec, fi, fi); - delete [] fi; -} - -//===================================================================== -// Filter will the Hilbert form -//===================================================================== - -void C_FIR_filter::init_hilbert (int len, int dec) { - double *fi = bp_FIR(len, 0, 0.05, 0.45); - double *fq = bp_FIR(len, 1, 0.05, 0.45); - init (len, dec, fi, fq); - delete [] fi; - delete [] fq; -} - - -//===================================================================== -// Run -// passes a cmplx value (in) and receives the cmplx value (out) -// function returns 0 if the filter is not yet stable -// returns 1 when stable and decimated cmplx output value is valid -//===================================================================== - -int C_FIR_filter::run (const cmplx &in, cmplx &out) { - ibuffer[pointer] = in.real(); - qbuffer[pointer] = in.imag(); - counter++; - if (counter == decimateratio) - out = cmplx ( mac(&ibuffer[pointer - length], ifilter, length), - mac(&qbuffer[pointer - length], qfilter, length) ); - pointer++; - if (pointer == FIRBufferLen) { - /// memmove is necessary if length >= FIRBufferLen/2 , theoretically possible. - memmove (ibuffer, ibuffer + FIRBufferLen - length, length * sizeof (double) ); - memmove (qbuffer, qbuffer + FIRBufferLen - length, length * sizeof (double) ); - pointer = length; - } - if (counter == decimateratio) { - counter = 0; - return 1; - } - return 0; -} - -//===================================================================== -// Run the filter for the Real part of the cmplx variable -//===================================================================== - -int C_FIR_filter::Irun (const double &in, double &out) { - double *iptr = ibuffer + pointer; - - pointer++; - counter++; - - *iptr = in; - - if (counter == decimateratio) { - out = mac(iptr - length, ifilter, length); - } - - if (pointer == FIRBufferLen) { - iptr = ibuffer + FIRBufferLen - length; - memcpy(ibuffer, iptr, length * sizeof(double)); - pointer = length; - } - - if (counter == decimateratio) { - counter = 0; - return 1; - } - - return 0; -} - -//===================================================================== -// Run the filter for the Imaginary part of the cmplx variable -//===================================================================== - -int C_FIR_filter::Qrun (const double &in, double &out) { - double *qptr = ibuffer + pointer; - - pointer++; - counter++; - - *qptr = in; - - if (counter == decimateratio) { - out = mac(qptr - length, qfilter, length); - } - - if (pointer == FIRBufferLen) { - qptr = qbuffer + FIRBufferLen - length; - memcpy(qbuffer, qptr, length * sizeof(double)); - pointer = length; - } - - if (counter == decimateratio) { - counter = 0; - return 1; - } - - return 0; -} - - -//===================================================================== -// Moving average filter -// -// Simple in concept, sublime in implementation ... the fastest filter -// in the west. Also optimal for the processing of time domain signals -// characterized by a transition edge. The is the perfect signal filter -// for CW, RTTY and other signals of that type. For a given filter size -// it provides the greatest s/n improvement while retaining the sharpest -// leading edge on the filtered signal. -//===================================================================== - -Cmovavg::Cmovavg (int filtlen) -{ - len = filtlen; - in = new double[len]; - empty = true; -} - -Cmovavg::~Cmovavg() -{ - if (in) delete [] in; -} - -double Cmovavg::run(double a) -{ - if (!in) { - return a; - } - if (empty) { - empty = false; - out = 0; - for (int i = 0; i < len; i++) { - in[i] = a; - out += a; - } - pint = 0; - return a; - } - out = out - in[pint] + a; - in[pint] = a; - if (++pint >= len) pint = 0; - return out / len; -} - -void Cmovavg::setLength(int filtlen) -{ - if (filtlen > len) { - if (in) delete [] in; - in = new double[filtlen]; - } - len = filtlen; - empty = true; -} - -void Cmovavg::reset() -{ - empty = true; -} - -//===================================================================== -// Sliding FFT filter -// Sliding Fast Fourier Transform -// -// The sliding FFT ingeniously exploits the properties of a time-delayed -// input and the property of linearity for its derivation. -// -// First of all, the N-point transform of a sequence x(n) is equal to the -// summation of the transforms of N separate transforms where each transform -// has just one of the original samples at it's original sample time. -// -//i.e. -// transform of [x0, x1, x2, x3, x4, x5,...xN-1] -// is equal to -// transform of [x0, 0, 0, 0, 0, 0,...0] -// + transform of [0, x1, 0, 0, 0, 0,...0] -// + transform of [0, 0, x2, 0, 0, 0,...0] -// + transform of [0, 0, 0, x3, 0, 0,...0] -// . -// . -// . -// + transform of [0, 0, 0, 0, 0, 0,...xN-1] -// -// Secondly, the transform of a time-delayed sequence is a phase-rotated -// version of the transform of the original sequence. i.e. -// -// If x(n) transforms to X(k), -// Then x(n-m) transforms to X(k)(Wn)^(-mk) -// -// where N is the FFT size, m is the delay in sample periods, and WN is the -// familiar phase-rotating coefficient or twiddle factor e^(-j2p/N) -// -// Therefore, if the N-point transform X(k) of an individual sample is considered, -// and then the sample is moved back in time by one sample period, all frequency -// bins of X(k) are phase-rotated by 2pk/N radians. -// -// The important thing here is that the transform is not performed again because -// the previous frequency results can be used by simply application of the correct -// coefficients. -// -// This is the technique that is applied when the rectangular sampling window -// slides along by one sample. The contributions of all samples that are -// included in both the original and the new windows are simply phase rotated. -// The end effects are that the transform of the new sample must be added, and -// the transform of the oldest sample that disappeared off the end must be -// subtracted. These end-effects are easy to perform if we treat the new sample -// as occurring at time t = 0, because the transform of a single sample at t = 0, -// say (a + bj), simply has all frequency bins equal to (a + bj). Similarly, the -// oldest sample that has just disappeared off the end of the window is exactly N -// samples old. I.e. it occurred at t = -N. The transform of this sample, -// say (c + dj), is also straightforward since every frequency bin has now been -// phase-rotated an integer number of times from when the sample was at t = 0. -// (The kth frequency bin has been rotated by 2pk radians). The transform of the -// sample at t = -N is therefore the same as if it was still at t = 0. I.e. it -// has all frequency bins equal to (c + dj). -// -// All that is needed therefore is to -// phase rotate each frequency bin in F(k) by WN^(k) and then -// add [(a + bj) + (c + dj)] to each frequency bin. -// -// One cmplx multiplication and two cmplx additions per frequency bin are -// therefore required, per sample period, regardless of the size of the transform. -// -// For example, a traditional 1024-point FFT needs 5120 cmplx multiplies -// and 10240 cmplx additions to calculate all 1024 frequency bins. A 1024-point -// Sliding FFT however needs 1024 cmplx multiplies and 2048 cmplx additions -// for all 1024 frequency bins, and as each frequency bin is calculated separately, -// it is only necessary to calculate the ones that are of interest. -// -// One drawback of the Sliding FFT is that in using feedback from previous -// frequency bins, there is potential for instability if the coefficients are not -// infinitely precise. Without infinite precision, stability can be guaranteed by -// making each phase-rotation coefficient have a magnitude of slightly less than -// unity. E.g. 0.9999. -// -// This then has to taken into account when the Nth sample is subtracted, because -// the factor 0.9999 has been applied N times to the transform of this sample. -// The sample cannot therefore be directly subtracted, it must first be multiplied -// by the factor of 0.9999^N. This unfortunately means there is another multipli- -// cation to perform per frequency bin. Another drawback is that a circular buffer -// is needed in which to keep N samples, so that the oldest sample, (from t= -N), -// can be subtracted each time. -// -// This filter is ideal for extracting a finite number of frequency bins -// with a very long kernel length. The filter only needs to calculate the -// values for the bins of interest and not the entire spectrum. It does -// require the store of the history associated with those bins over the -// kernel length. -// -// Use in the MFSK / DOMINO modem for extraction of the frequency spectra -// -//===================================================================== - -struct sfft::vrot_bins_pair { - cmplx vrot; - cmplx bins; -} ; - -sfft::sfft(int len, int _first, int _last) -{ - vrot_bins = new vrot_bins_pair[len]; - delay = new cmplx[len]; - fftlen = len; - first = _first; - last = _last; - ptr = 0; - double phi = 0.0, tau = 2.0 * M_PI/ len; - k2 = 1.0; - for (int i = 0; i < fftlen; i++) { - vrot_bins[i].vrot = cmplx( K1 * cos (phi), K1 * sin (phi) ); - phi += tau; - delay[i] = vrot_bins[i].bins = 0.0; - k2 *= K1; - } - count = 0; -} - -sfft::~sfft() -{ - delete [] vrot_bins; - delete [] delay; -} - -void sfft::reset() -{ - for (int i = 0; i < fftlen; i++) delay[i] = vrot_bins[i].bins = 0.0; - count = 0; -} - -bool sfft::is_stable() -{ - return (count >= fftlen); -} - -// Sliding FFT, cmplx input, cmplx output -// FFT is computed for each value from first to last -// Values are not stable until more than "len" samples have been processed. -// Copies the frequencies to a pointer with a given stride. -void sfft::run(const cmplx& input, cmplx * __restrict__ result, int stride ) -{ - cmplx & de = delay[ptr]; - const cmplx z( input.real() - k2 * de.real(), input.imag() - k2 * de.imag()); - de = input; - - ++ptr ; - if( ptr >= fftlen ) ptr = 0 ; - - // It is more efficient to have vrot and bins very close to each other. - for( vrot_bins_pair - * __restrict__ itr = vrot_bins + first, - * __restrict__ end = vrot_bins + last ; - itr != end ; - ++itr, result += stride ) { - *result = itr->bins = itr->bins * itr->vrot + z * itr->vrot; - } - if (count < fftlen) count++; -} - -// ============================================================================ -// Goertzel filter -// Optimized implementation of a DFT for a single frequency of interest -// SR = sample rate -// N = Block size (does not need to be a factor of 2!) -// bin size = SR / N -// K = frequency bin of interest = (N * freq / SR) -// N should be selected to make K an integer if possible -// -// Q0 = current sample -// Q1 = previous sample (1 delay) -// Q2 = previous sample (2 delay) -// w = (2 * pi * K / N) -// k1 = cos(w) -// k2 = sin(w) -// k3 = 2.0 * k1 - -// Q0, Q1, Q2 are initialized to zero -// Iterate N times: -// Q0 = k3*Q1 - Q2 + sample -// Q2 = Q1 -// Q1 = Q0 -// -// After N interations: -// real = (Q1 - Q2 * k1) -// imag = Q2 * k2 -// or -// mag = Q1*Q1 + Q2*Q2 - Q1*Q2*k1 -// ============================================================================ - -goertzel::goertzel(int n, double freq, double sr) -{ - double w; - w = 2 * M_PI * freq / sr; - k1 = cos(w); - k2 = sin(w); - k3 = 2.0 * k1; - Q0 = Q1 = Q2 = 0.0; - count = N = n; -} - -goertzel::~goertzel() -{ -} - -void goertzel::reset() -{ - Q0 = Q1 = Q2 = 0.0; - count = N; -} - -void goertzel::reset(int n, double freq, double sr) -{ - double w; - w = 2 * M_PI * freq / sr; - k1 = cos(w); - k2 = sin(w); - k3 = 2.0 * k1; - Q0 = Q1 = Q2 = 0.0; - count = N = n; -} - -bool goertzel::run(double sample) -{ - Q0 = sample + k3*Q1 - Q2; - Q2 = Q1; - Q1 = Q0; - if (count) { --count; return false; } - return true; -} - -double goertzel::real() -{ - return ((0.5*k3*Q1 - Q2)/N); -} - -double goertzel::imag() -{ - return ((k2*Q1)/N); -} - -double goertzel::mag() -{ - return (Q2*Q2 + Q1*Q1 - k3*Q2*Q1); -} diff --git a/feature/cw/src/main/cpp/fldigi/filters.h b/feature/cw/src/main/cpp/fldigi/filters.h deleted file mode 100644 index eee71909..00000000 --- a/feature/cw/src/main/cpp/fldigi/filters.h +++ /dev/null @@ -1,183 +0,0 @@ -// ---------------------------------------------------------------------------- -// -// filters.h -- Several Digital Filter classes used in fldigi -// -// Copyright (C) 2006-2008 -// Dave Freese, W1HKJ -// -// This file is part of fldigi. These filters are based on the -// gmfsk design and the design notes given in -// "Digital Signal Processing", A Practical Guid for Engineers and Scientists -// by Steven W. Smith. -// -// Fldigi 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. -// -// Fldigi 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 fldigi. If not, see . -// ---------------------------------------------------------------------------- - - -#ifndef _FILTER_H -#define _FILTER_H - -#include "complex.h" -#ifndef M_PI -#define M_PI (3.1415926535897932385) -#endif - -//===================================================================== -// FIR filters -//===================================================================== - -class C_FIR_filter { -#define FIRBufferLen 4096 -private: - int length; - int decimateratio; - - double *ifilter; - double *qfilter; - - double ffreq; - - double ibuffer[FIRBufferLen]; - double qbuffer[FIRBufferLen]; - - int pointer; - int counter; - - cmplx fu; - - inline double sinc(double x) { - if (fabs(x) < 1e-10) - return 1.0; - else - return sin(M_PI * x) / (M_PI * x); - } - inline double cosc(double x) { - if (fabs(x) < 1e-10) - return 0.0; - else - return (1.0 - cos(M_PI * x)) / (M_PI * x); - } - inline double hamming(double x) { - return 0.54 - 0.46 * cos(2 * M_PI * x); - } - inline double mac(const double *a, const double *b, unsigned int size) { - double sum = 0.0; - double sum2 = 0.0; - double sum3 = 0.0; - double sum4 = 0.0; - // Reduces read-after-write dependencies : Each subsum does not wait for the others. - // The CPU can therefore schedule each line independently. - for (; size > 3; size -= 4, a += 4, b+=4) - { - sum += a[0] * b[0]; - sum2 += a[1] * b[1]; - sum3 += a[2] * b[2]; - sum4 += a[3] * b[3]; - } - for (; size; --size) - sum += (*a++) * (*b++); - return sum + sum2 + sum3 + sum4 ; - } - -protected: - -public: - C_FIR_filter (); - ~C_FIR_filter (); - - void init (int len, int dec, double *ifil, double *qfil); - void init_lowpass (int len, int dec, double freq ); - void init_bandpass (int len, int dec, double freq1, double freq2); - void init_hilbert (int len, int dec); - double *bp_FIR(int len, int hilbert, double f1, double f2); - - void clear(); - int run (const cmplx &in, cmplx &out); - int Irun (const double &in, double &out); - int Qrun (const double &in, double &out); -}; - -//===================================================================== -// Moving average filter -//===================================================================== - -class Cmovavg { -#define MAXMOVAVG 2048 -private: - double *in; - double out; - int len, pint; - bool empty; -public: - Cmovavg(int filtlen = 64); - ~Cmovavg(); - double run(double a); - void setLength(int filtlen); - void reset(); - double value() { return out / (len > 0 ? len : 1); } -}; - - -//===================================================================== -// Sliding FFT -//===================================================================== - -class sfft { -#define K1 0.99999999999L -private: - int fftlen; - int first; - int last; - int ptr; - struct vrot_bins_pair ; - vrot_bins_pair * __restrict__ vrot_bins ; - cmplx * __restrict__ delay; - double k2; - int count; -public: - sfft(int len, int first, int last); - ~sfft(); - bool is_stable(); - void reset(); - void run(const cmplx& input, cmplx * __restrict__ result, int stride ); -}; - - - -//============================================================================= -// Goertzel DFT -//============================================================================= - -class goertzel { -private: - int N; - int count; - double Q0; - double Q1; - double Q2; - double k1; - double k2; - double k3; -public: - goertzel(int n, double freq, double sr); - ~goertzel(); - void reset(); - void reset(int n, double freq, double sr); - bool run(double v); - double real(); - double imag(); - double mag(); -}; - -#endif /* _FILTER_H */ diff --git a/feature/cw/src/main/cpp/fldigi/gfft.h b/feature/cw/src/main/cpp/fldigi/gfft.h deleted file mode 100644 index eaadf3db..00000000 --- a/feature/cw/src/main/cpp/fldigi/gfft.h +++ /dev/null @@ -1,3392 +0,0 @@ -//============================================================================== -// g_fft.h: -// -// FFT library -// Copyright (C) 2013 -// Dave Freese, W1HKJ -// -// based on public domain code by John Green -// original version is available at -// http://hyperarchive.lcs.mit.edu/ -// /HyperArchive/Archive/dev/src/ffts-for-risc-2-c.hqx -// -// ported to C++ for fldigi by Dave Freese, W1HKJ -// -// This file is part of fldigi. -// -// Fldigi is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Fldigi 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 fldigi. If not, see . -//============================================================================== -//============================================================================== -// Original Green C implementation written as a C++ template -// Code has been tested for types -// g_fft -// g_fft -// g_fft -// g_fft -// where the xxx types perform better than the xxx_t types -// typical performance for 8192 point fft on an Intel(R) Pentium(R) Dual -// CPU E2180 @ 2.00GHz -// type complex_fwd real_fwd -// double 0.407 ms 0.203 ms -// double_t 1.269 ms 0.593 ms -// float 0.385 ms 0.193 ms -// float_t 1.160 ms 0.627 ms -//============================================================================== - -#ifndef CGREEN_FFT_H -#define CGREEN_FFT_H - -#include - -template -class g_fft { -#define FFT_RECIPLN2 1.442695040888963407359924681001892137426 // 1.0/log(2) - -// some useful conversions between a number and its power of 2 -#define LOG2(a) (FFT_RECIPLN2*log(a)) // floating point logarithm base 2 -#define POW2(m) ((unsigned int) 1 << (m)) // integer power of 2 for m<32 - -// fft's with M bigger than this bust primary cache -#define MCACHE (11 - (sizeof(FFT_TYPE) / 8)) - -// some math constants to 40 decimal places -#define FFT_PI 3.141592653589793238462643383279502884197 // pi -#define FFT_ROOT2 1.414213562373095048801688724209698078569 // sqrt(2) -#define FFT_COSPID8 0.9238795325112867561281831893967882868224 // cos(pi/8) -#define FFT_SINPID8 0.3826834323650897717284599840303988667613 // sin(pi/8) -private: - int FFT_size; - int FFT_N; - FFT_TYPE *FFT_table_1[32]; - short int *FFT_table_2[32]; - - FFT_TYPE *Utbl; - short *BRLow; - - void fftInit(); - int ConvertFFTSize(int); - -// base fft methods - void riffts1(FFT_TYPE *ioptr, int M, FFT_TYPE *Utbl, short *BRLow); - void ifrstage(FFT_TYPE *ioptr, int M, FFT_TYPE *Utbl); - void rifft8pt(FFT_TYPE *ioptr, FFT_TYPE scale); - void rifft4pt(FFT_TYPE *ioptr, FFT_TYPE scale); - void rifft2pt(FFT_TYPE *ioptr, FFT_TYPE scale); - void rifft1pt(FFT_TYPE *ioptr, FFT_TYPE scale); - void rffts1(FFT_TYPE *ioptr, int M, FFT_TYPE *Utbl, short *BRLow); - void frstage(FFT_TYPE *ioptr, int M, FFT_TYPE *Utbl); - void rfft8pt(FFT_TYPE *ioptr); - void rfft4pt(FFT_TYPE *ioptr); - void rfft2pt(FFT_TYPE *ioptr); - void rfft1pt(FFT_TYPE *ioptr); - void iffts1(FFT_TYPE *ioptr, int M, FFT_TYPE *Utbl, short *BRLow); - void ifftrecurs(FFT_TYPE *ioptr, int M, FFT_TYPE *Utbl, int Ustride, - int NDiffU, int StageCnt); - void ibfstages(FFT_TYPE *ioptr, int M, FFT_TYPE *Utbl, int Ustride, - int NDiffU, int StageCnt); - void ibfR4(FFT_TYPE *ioptr, int M, int NDiffU); - void ibfR2(FFT_TYPE *ioptr, int M, int NDiffU); - void ifft8pt(FFT_TYPE *ioptr, FFT_TYPE scale); - void ifft4pt(FFT_TYPE *ioptr, FFT_TYPE scale); - void ifft2pt(FFT_TYPE *ioptr, FFT_TYPE scale); - void scbitrevR2(FFT_TYPE *ioptr, int M, short *BRLow, FFT_TYPE scale); - void ffts1(FFT_TYPE *ioptr, int M, FFT_TYPE *Utbl, short *BRLow); - void fftrecurs(FFT_TYPE *ioptr, int M, - FFT_TYPE *Utbl, int Ustride, int NDiffU, - int StageCnt); - void bfstages(FFT_TYPE *ioptr, int M, - FFT_TYPE *Utbl, int Ustride, - int NDiffU, int StageCnt); - void bfR4(FFT_TYPE *ioptr, int M, int NDiffU); - void bfR2(FFT_TYPE *ioptr, int M, int NDiffU); - void fft8pt(FFT_TYPE *ioptr); - void fft4pt(FFT_TYPE *ioptr); - void fft2pt(FFT_TYPE *ioptr); - void bitrevR2(FFT_TYPE *ioptr, int M, short *BRLow); - void fftBRInit(int M, short *BRLow); - void fftCosInit(int M, FFT_TYPE *Utbl); - -public: - g_fft(int M = 8192) { - if (M < 16) M = 16; - if (M > 268435456) M = 268435456; - FFT_size = M; - fftInit(); - } - ~g_fft() { - for (int i = 0; i < 32; i++) { - if (FFT_table_1[i] != 0) delete [] FFT_table_1[i]; - if (FFT_table_2[i] != 0) delete [] FFT_table_2[i]; - } - } - - void ComplexFFT(std::complex *buf); - void InverseComplexFFT(std::complex *buf); - void RealFFT(std::complex *buf); - void InverseRealFFT(std::complex *buf); - FFT_TYPE GetInverseComplexFFTScale(); - FFT_TYPE GetInverseRealFFTScale(); -}; - -//------------------------------------------------------------------------------ -// Compute Utbl, the cosine table for ffts -// of size (pow(2,M)/4 +1) -// INPUTS -// M = log2 of fft size -// OUTPUTS -// *Utbl = cosine table -//------------------------------------------------------------------------------ -template -void g_fft::fftCosInit(int M, FFT_TYPE *Utbl) -{ - unsigned int fftN = POW2(M); - unsigned int i1; - - Utbl[0] = FFT_TYPE(1.0); - for (i1 = 1; i1 < fftN/4; i1++) - Utbl[i1] = (FFT_TYPE)cos((2.0 * FFT_PI * (double)i1) / (double)fftN); - Utbl[fftN/4] = FFT_TYPE(0.0); -} - -//------------------------------------------------------------------------------ -// Compute BRLow, the bit reversed table for ffts -// of size pow(2,M/2 -1) -// INPUTS -// M = log2 of fft size -// OUTPUTS -// *BRLow = bit reversed counter table -//------------------------------------------------------------------------------ -template -void g_fft::fftBRInit(int M, short *BRLow) -{ - int Mroot_1 = M / 2 - 1; - int Nroot_1 = POW2(Mroot_1); - int i1; - int bitsum; - int bitmask; - int bit; - - for (i1 = 0; i1 < Nroot_1; i1++) { - bitsum = 0; - bitmask = 1; - for (bit = 1; bit <= Mroot_1; bitmask <<= 1, bit++) - if (i1 & bitmask) - bitsum = bitsum + (Nroot_1 >> bit); - BRLow[i1] = bitsum; - } -} - -//------------------------------------------------------------------------------ -// parts of ffts1 -// bit reverse and first radix 2 stage of forward or inverse fft -//------------------------------------------------------------------------------ -template -void g_fft::bitrevR2(FFT_TYPE *ioptr, int M, short *BRLow) -{ - FFT_TYPE f0r; - FFT_TYPE f0i; - FFT_TYPE f1r; - FFT_TYPE f1i; - FFT_TYPE f2r; - FFT_TYPE f2i; - FFT_TYPE f3r; - FFT_TYPE f3i; - FFT_TYPE f4r; - FFT_TYPE f4i; - FFT_TYPE f5r; - FFT_TYPE f5i; - FFT_TYPE f6r; - FFT_TYPE f6i; - FFT_TYPE f7r; - FFT_TYPE f7i; - FFT_TYPE t0r; - FFT_TYPE t0i; - FFT_TYPE t1r; - FFT_TYPE t1i; - FFT_TYPE *p0r; - FFT_TYPE *p1r; - FFT_TYPE *IOP; - FFT_TYPE *iolimit; - int Colstart; - int iCol; - unsigned int posA; - unsigned int posAi; - unsigned int posB; - unsigned int posBi; - - const unsigned int Nrems2 = POW2((M + 3) / 2); - const unsigned int Nroot_1_ColInc = POW2(M) - Nrems2; - const unsigned int Nroot_1 = POW2(M / 2 - 1) - 1; - const unsigned int ColstartShift = (M + 1) / 2 + 1; - - posA = POW2(M); // 1/2 of POW2(M) complex - posAi = posA + 1; - posB = posA + 2; - posBi = posB + 1; - - iolimit = ioptr + Nrems2; - for (; ioptr < iolimit; ioptr += POW2(M / 2 + 1)) { - for (Colstart = Nroot_1; Colstart >= 0; Colstart--) { - iCol = Nroot_1; - p0r = ioptr + Nroot_1_ColInc + BRLow[Colstart] * 4; - IOP = ioptr + (Colstart << ColstartShift); - p1r = IOP + BRLow[iCol] * 4; - f0r = *(p0r); - f0i = *(p0r + 1); - f1r = *(p0r + posA); - f1i = *(p0r + posAi); - for (; iCol > Colstart;) { - f2r = *(p0r + 2); - f2i = *(p0r + (2 + 1)); - f3r = *(p0r + posB); - f3i = *(p0r + posBi); - f4r = *(p1r); - f4i = *(p1r + 1); - f5r = *(p1r + posA); - f5i = *(p1r + posAi); - f6r = *(p1r + 2); - f6i = *(p1r + (2 + 1)); - f7r = *(p1r + posB); - f7i = *(p1r + posBi); - - t0r = f0r + f1r; - t0i = f0i + f1i; - f1r = f0r - f1r; - f1i = f0i - f1i; - t1r = f2r + f3r; - t1i = f2i + f3i; - f3r = f2r - f3r; - f3i = f2i - f3i; - f0r = f4r + f5r; - f0i = f4i + f5i; - f5r = f4r - f5r; - f5i = f4i - f5i; - f2r = f6r + f7r; - f2i = f6i + f7i; - f7r = f6r - f7r; - f7i = f6i - f7i; - - *(p1r) = t0r; - *(p1r + 1) = t0i; - *(p1r + 2) = f1r; - *(p1r + (2 + 1)) = f1i; - *(p1r + posA) = t1r; - *(p1r + posAi) = t1i; - *(p1r + posB) = f3r; - *(p1r + posBi) = f3i; - *(p0r) = f0r; - *(p0r + 1) = f0i; - *(p0r + 2) = f5r; - *(p0r + (2 + 1)) = f5i; - *(p0r + posA) = f2r; - *(p0r + posAi) = f2i; - *(p0r + posB) = f7r; - *(p0r + posBi) = f7i; - - p0r -= Nrems2; - f0r = *(p0r); - f0i = *(p0r + 1); - f1r = *(p0r + posA); - f1i = *(p0r + posAi); - iCol -= 1; - p1r = IOP + BRLow[iCol] * 4; - } - f2r = *(p0r + 2); - f2i = *(p0r + (2 + 1)); - f3r = *(p0r + posB); - f3i = *(p0r + posBi); - - t0r = f0r + f1r; - t0i = f0i + f1i; - f1r = f0r - f1r; - f1i = f0i - f1i; - t1r = f2r + f3r; - t1i = f2i + f3i; - f3r = f2r - f3r; - f3i = f2i - f3i; - - *(p0r) = t0r; - *(p0r + 1) = t0i; - *(p0r + 2) = f1r; - *(p0r + (2 + 1)) = f1i; - *(p0r + posA) = t1r; - *(p0r + posAi) = t1i; - *(p0r + posB) = f3r; - *(p0r + posBi) = f3i; - } - } -} - -//------------------------------------------------------------------------------ -// RADIX 2 fft -//------------------------------------------------------------------------------ -template -void g_fft::fft2pt(FFT_TYPE *ioptr) -{ - FFT_TYPE f0r, f0i, f1r, f1i; - FFT_TYPE t0r, t0i; - -// bit reversed load - f0r = ioptr[0]; - f0i = ioptr[1]; - f1r = ioptr[2]; - f1i = ioptr[3]; - -// Butterflys -// f0 - - - t0 -// f1 - 1 - f1 - - t0r = f0r + f1r; - t0i = f0i + f1i; - f1r = f0r - f1r; - f1i = f0i - f1i; - -// store result - ioptr[0] = t0r; - ioptr[1] = t0i; - ioptr[2] = f1r; - ioptr[3] = f1i; -} - -//------------------------------------------------------------------------------ -// RADIX 4 fft -//------------------------------------------------------------------------------ -template -void g_fft::fft4pt(FFT_TYPE *ioptr) -{ - FFT_TYPE f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; - FFT_TYPE t0r, t0i, t1r, t1i; - -// bit reversed load - f0r = ioptr[0]; - f0i = ioptr[1]; - f1r = ioptr[4]; - f1i = ioptr[5]; - f2r = ioptr[2]; - f2i = ioptr[3]; - f3r = ioptr[6]; - f3i = ioptr[7]; - -// Butterflys -// f0 - - t0 - - f0 -// f1 - 1 - f1 - - f1 -// f2 - - f2 - 1 - f2 -// f3 - 1 - t1 - -i - f3 - - t0r = f0r + f1r; - t0i = f0i + f1i; - f1r = f0r - f1r; - f1i = f0i - f1i; - - t1r = f2r - f3r; - t1i = f2i - f3i; - f2r = f2r + f3r; - f2i = f2i + f3i; - - f0r = t0r + f2r; - f0i = t0i + f2i; - f2r = t0r - f2r; - f2i = t0i - f2i; - - f3r = f1r - t1i; - f3i = f1i + t1r; - f1r = f1r + t1i; - f1i = f1i - t1r; - -// store result - ioptr[0] = f0r; - ioptr[1] = f0i; - ioptr[2] = f1r; - ioptr[3] = f1i; - ioptr[4] = f2r; - ioptr[5] = f2i; - ioptr[6] = f3r; - ioptr[7] = f3i; -} - -//------------------------------------------------------------------------------ -// RADIX 8 fft -//------------------------------------------------------------------------------ -template -void g_fft::fft8pt(FFT_TYPE *ioptr) -{ - FFT_TYPE w0r = 1.0 / FFT_ROOT2; // cos(pi/4) - FFT_TYPE f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; - FFT_TYPE f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i; - FFT_TYPE t0r, t0i, t1r, t1i; - const FFT_TYPE Two = 2.0; - -// bit reversed load - f0r = ioptr[0]; - f0i = ioptr[1]; - f1r = ioptr[8]; - f1i = ioptr[9]; - f2r = ioptr[4]; - f2i = ioptr[5]; - f3r = ioptr[12]; - f3i = ioptr[13]; - f4r = ioptr[2]; - f4i = ioptr[3]; - f5r = ioptr[10]; - f5i = ioptr[11]; - f6r = ioptr[6]; - f6i = ioptr[7]; - f7r = ioptr[14]; - f7i = ioptr[15]; - -// Butterflys -// f0 - - t0 - - f0 - - f0 -// f1 - 1 - f1 - - f1 - - f1 -// f2 - - f2 - 1 - f2 - - f2 -// f3 - 1 - t1 - -i - f3 - - f3 -// f4 - - t0 - - f4 - 1 - t0 -// f5 - 1 - f5 - - f5 - w3 - f4 -// f6 - - f6 - 1 - f6 - -i - t1 -// f7 - 1 - t1 - -i - f7 - iw3- f6 - - t0r = f0r + f1r; - t0i = f0i + f1i; - f1r = f0r - f1r; - f1i = f0i - f1i; - - t1r = f2r - f3r; - t1i = f2i - f3i; - f2r = f2r + f3r; - f2i = f2i + f3i; - - f0r = t0r + f2r; - f0i = t0i + f2i; - f2r = t0r - f2r; - f2i = t0i - f2i; - - f3r = f1r - t1i; - f3i = f1i + t1r; - f1r = f1r + t1i; - f1i = f1i - t1r; - - t0r = f4r + f5r; - t0i = f4i + f5i; - f5r = f4r - f5r; - f5i = f4i - f5i; - - t1r = f6r - f7r; - t1i = f6i - f7i; - f6r = f6r + f7r; - f6i = f6i + f7i; - - f4r = t0r + f6r; - f4i = t0i + f6i; - f6r = t0r - f6r; - f6i = t0i - f6i; - - f7r = f5r - t1i; - f7i = f5i + t1r; - f5r = f5r + t1i; - f5i = f5i - t1r; - - t0r = f0r - f4r; - t0i = f0i - f4i; - f0r = f0r + f4r; - f0i = f0i + f4i; - - t1r = f2r - f6i; - t1i = f2i + f6r; - f2r = f2r + f6i; - f2i = f2i - f6r; - - f4r = f1r - f5r * w0r - f5i * w0r; - f4i = f1i + f5r * w0r - f5i * w0r; - f1r = f1r * Two - f4r; - f1i = f1i * Two - f4i; - - f6r = f3r + f7r * w0r - f7i * w0r; - f6i = f3i + f7r * w0r + f7i * w0r; - f3r = f3r * Two - f6r; - f3i = f3i * Two - f6i; - -// store result - ioptr[0] = f0r; - ioptr[1] = f0i; - ioptr[2] = f1r; - ioptr[3] = f1i; - ioptr[4] = f2r; - ioptr[5] = f2i; - ioptr[6] = f3r; - ioptr[7] = f3i; - ioptr[8] = t0r; - ioptr[9] = t0i; - ioptr[10] = f4r; - ioptr[11] = f4i; - ioptr[12] = t1r; - ioptr[13] = t1i; - ioptr[14] = f6r; - ioptr[15] = f6i; -} - -//------------------------------------------------------------------------------ -// 2nd radix 2 stage -//------------------------------------------------------------------------------ -template -void g_fft::bfR2(FFT_TYPE *ioptr, int M, int NDiffU) -{ - unsigned int pos; - unsigned int posi; - unsigned int pinc; - unsigned int pnext; - unsigned int NSameU; - unsigned int SameUCnt; - - FFT_TYPE *pstrt; - FFT_TYPE *p0r, *p1r, *p2r, *p3r; - - FFT_TYPE f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; - FFT_TYPE f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i; - - pinc = NDiffU * 2; // 2 floats per complex - pnext = pinc * 4; - pos = 2; - posi = pos + 1; - NSameU = POW2(M) / 4 / NDiffU; // 4 Us at a time - pstrt = ioptr; - p0r = pstrt; - p1r = pstrt + pinc; - p2r = p1r + pinc; - p3r = p2r + pinc; - -// Butterflys -// f0 - - f4 -// f1 - 1 - f5 -// f2 - - f6 -// f3 - 1 - f7 -// Butterflys -// f0 - - f4 -// f1 - 1 - f5 -// f2 - - f6 -// f3 - 1 - f7 - - for (SameUCnt = NSameU; SameUCnt > 0; SameUCnt--) { - - f0r = *p0r; - f1r = *p1r; - f0i = *(p0r + 1); - f1i = *(p1r + 1); - f2r = *p2r; - f3r = *p3r; - f2i = *(p2r + 1); - f3i = *(p3r + 1); - - f4r = f0r + f1r; - f4i = f0i + f1i; - f5r = f0r - f1r; - f5i = f0i - f1i; - - f6r = f2r + f3r; - f6i = f2i + f3i; - f7r = f2r - f3r; - f7i = f2i - f3i; - - *p0r = f4r; - *(p0r + 1) = f4i; - *p1r = f5r; - *(p1r + 1) = f5i; - *p2r = f6r; - *(p2r + 1) = f6i; - *p3r = f7r; - *(p3r + 1) = f7i; - - f0r = *(p0r + pos); - f1i = *(p1r + posi); - f0i = *(p0r + posi); - f1r = *(p1r + pos); - f2r = *(p2r + pos); - f3i = *(p3r + posi); - f2i = *(p2r + posi); - f3r = *(p3r + pos); - - f4r = f0r + f1i; - f4i = f0i - f1r; - f5r = f0r - f1i; - f5i = f0i + f1r; - - f6r = f2r + f3i; - f6i = f2i - f3r; - f7r = f2r - f3i; - f7i = f2i + f3r; - - *(p0r + pos) = f4r; - *(p0r + posi) = f4i; - *(p1r + pos) = f5r; - *(p1r + posi) = f5i; - *(p2r + pos) = f6r; - *(p2r + posi) = f6i; - *(p3r + pos) = f7r; - *(p3r + posi) = f7i; - - p0r += pnext; - p1r += pnext; - p2r += pnext; - p3r += pnext; - } -} - -//------------------------------------------------------------------------------ -// 1 radix 4 stage -//------------------------------------------------------------------------------ -template -void g_fft::bfR4(FFT_TYPE *ioptr, int M, int NDiffU) -{ - unsigned int pos; - unsigned int posi; - unsigned int pinc; - unsigned int pnext; - unsigned int pnexti; - unsigned int NSameU; - unsigned int SameUCnt; - - FFT_TYPE *pstrt; - FFT_TYPE *p0r, *p1r, *p2r, *p3r; - - FFT_TYPE w1r = 1.0 / FFT_ROOT2; // cos(pi/4) - FFT_TYPE f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; - FFT_TYPE f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i; - FFT_TYPE t1r, t1i; - const FFT_TYPE Two = 2.0; - - pinc = NDiffU * 2; // 2 floats per complex - pnext = pinc * 4; - pnexti = pnext + 1; - pos = 2; - posi = pos + 1; - NSameU = POW2(M) / 4 / NDiffU; // 4 pts per butterfly - pstrt = ioptr; - p0r = pstrt; - p1r = pstrt + pinc; - p2r = p1r + pinc; - p3r = p2r + pinc; - -// Butterflys -// f0 - - f0 - - f4 -// f1 - 1 - f5 - - f5 -// f2 - - f6 - 1 - f6 -// f3 - 1 - f3 - -i - f7 -// Butterflys -// f0 - - f4 - - f4 -// f1 - -i - t1 - - f5 -// f2 - - f2 - w1 - f6 -// f3 - -i - f7 - iw1- f7 - - f0r = *p0r; - f1r = *p1r; - f2r = *p2r; - f3r = *p3r; - f0i = *(p0r + 1); - f1i = *(p1r + 1); - f2i = *(p2r + 1); - f3i = *(p3r + 1); - - f5r = f0r - f1r; - f5i = f0i - f1i; - f0r = f0r + f1r; - f0i = f0i + f1i; - - f6r = f2r + f3r; - f6i = f2i + f3i; - f3r = f2r - f3r; - f3i = f2i - f3i; - - for (SameUCnt = NSameU - 1; SameUCnt > 0; SameUCnt--) { - - f7r = f5r - f3i; - f7i = f5i + f3r; - f5r = f5r + f3i; - f5i = f5i - f3r; - - f4r = f0r + f6r; - f4i = f0i + f6i; - f6r = f0r - f6r; - f6i = f0i - f6i; - - f2r = *(p2r + pos); - f2i = *(p2r + posi); - f1r = *(p1r + pos); - f1i = *(p1r + posi); - f3i = *(p3r + posi); - f0r = *(p0r + pos); - f3r = *(p3r + pos); - f0i = *(p0r + posi); - - *p3r = f7r; - *p0r = f4r; - *(p3r + 1) = f7i; - *(p0r + 1) = f4i; - *p1r = f5r; - *p2r = f6r; - *(p1r + 1) = f5i; - *(p2r + 1) = f6i; - - f7r = f2r - f3i; - f7i = f2i + f3r; - f2r = f2r + f3i; - f2i = f2i - f3r; - - f4r = f0r + f1i; - f4i = f0i - f1r; - t1r = f0r - f1i; - t1i = f0i + f1r; - - f5r = t1r - f7r * w1r + f7i * w1r; - f5i = t1i - f7r * w1r - f7i * w1r; - f7r = t1r * Two - f5r; - f7i = t1i * Two - f5i; - - f6r = f4r - f2r * w1r - f2i * w1r; - f6i = f4i + f2r * w1r - f2i * w1r; - f4r = f4r * Two - f6r; - f4i = f4i * Two - f6i; - - f3r = *(p3r + pnext); - f0r = *(p0r + pnext); - f3i = *(p3r + pnexti); - f0i = *(p0r + pnexti); - f2r = *(p2r + pnext); - f2i = *(p2r + pnexti); - f1r = *(p1r + pnext); - f1i = *(p1r + pnexti); - - *(p2r + pos) = f6r; - *(p1r + pos) = f5r; - *(p2r + posi) = f6i; - *(p1r + posi) = f5i; - *(p3r + pos) = f7r; - *(p0r + pos) = f4r; - *(p3r + posi) = f7i; - *(p0r + posi) = f4i; - - f6r = f2r + f3r; - f6i = f2i + f3i; - f3r = f2r - f3r; - f3i = f2i - f3i; - - f5r = f0r - f1r; - f5i = f0i - f1i; - f0r = f0r + f1r; - f0i = f0i + f1i; - - p3r += pnext; - p0r += pnext; - p1r += pnext; - p2r += pnext; - } - f7r = f5r - f3i; - f7i = f5i + f3r; - f5r = f5r + f3i; - f5i = f5i - f3r; - - f4r = f0r + f6r; - f4i = f0i + f6i; - f6r = f0r - f6r; - f6i = f0i - f6i; - - f2r = *(p2r + pos); - f2i = *(p2r + posi); - f1r = *(p1r + pos); - f1i = *(p1r + posi); - f3i = *(p3r + posi); - f0r = *(p0r + pos); - f3r = *(p3r + pos); - f0i = *(p0r + posi); - - *p3r = f7r; - *p0r = f4r; - *(p3r + 1) = f7i; - *(p0r + 1) = f4i; - *p1r = f5r; - *p2r = f6r; - *(p1r + 1) = f5i; - *(p2r + 1) = f6i; - - f7r = f2r - f3i; - f7i = f2i + f3r; - f2r = f2r + f3i; - f2i = f2i - f3r; - - f4r = f0r + f1i; - f4i = f0i - f1r; - t1r = f0r - f1i; - t1i = f0i + f1r; - - f5r = t1r - f7r * w1r + f7i * w1r; - f5i = t1i - f7r * w1r - f7i * w1r; - f7r = t1r * Two - f5r; - f7i = t1i * Two - f5i; - - f6r = f4r - f2r * w1r - f2i * w1r; - f6i = f4i + f2r * w1r - f2i * w1r; - f4r = f4r * Two - f6r; - f4i = f4i * Two - f6i; - - *(p2r + pos) = f6r; - *(p1r + pos) = f5r; - *(p2r + posi) = f6i; - *(p1r + posi) = f5i; - *(p3r + pos) = f7r; - *(p0r + pos) = f4r; - *(p3r + posi) = f7i; - *(p0r + posi) = f4i; -} - -//------------------------------------------------------------------------------ -// RADIX 8 Stages -//------------------------------------------------------------------------------ -template -void g_fft::bfstages(FFT_TYPE *ioptr, int M, FFT_TYPE *Utbl, int Ustride, - int NDiffU, int StageCnt) -{ - unsigned int pos; - unsigned int posi; - unsigned int pinc; - unsigned int pnext; - unsigned int NSameU; - int Uinc; - int Uinc2; - int Uinc4; - unsigned int DiffUCnt; - unsigned int SameUCnt; - unsigned int U2toU3; - - FFT_TYPE *pstrt; - FFT_TYPE *p0r, *p1r, *p2r, *p3r; - FFT_TYPE *u0r, *u0i, *u1r, *u1i, *u2r, *u2i; - - FFT_TYPE w0r, w0i, w1r, w1i, w2r, w2i, w3r, w3i; - FFT_TYPE f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; - FFT_TYPE f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i; - FFT_TYPE t0r, t0i, t1r, t1i; - const FFT_TYPE Two = FFT_TYPE(2.0); - - pinc = NDiffU * 2; // 2 floats per complex - pnext = pinc * 8; - pos = pinc * 4; - posi = pos + 1; - NSameU = POW2(M) / 8 / NDiffU; // 8 pts per butterfly - Uinc = (int) NSameU * Ustride; - Uinc2 = Uinc * 2; - Uinc4 = Uinc * 4; - U2toU3 = (POW2(M) / 8) * Ustride; - for (; StageCnt > 0; StageCnt--) { - - u0r = &Utbl[0]; - u0i = &Utbl[POW2(M - 2) * Ustride]; - u1r = u0r; - u1i = u0i; - u2r = u0r; - u2i = u0i; - - w0r = *u0r; - w0i = *u0i; - w1r = *u1r; - w1i = *u1i; - w2r = *u2r; - w2i = *u2i; - w3r = *(u2r + U2toU3); - w3i = *(u2i - U2toU3); - - pstrt = ioptr; - - p0r = pstrt; - p1r = pstrt + pinc; - p2r = p1r + pinc; - p3r = p2r + pinc; - -// Butterflys -// f0 - - t0 - - f0 - - f0 -// f1 - w0- f1 - - f1 - - f1 -// f2 - - f2 - w1- f2 - - f4 -// f3 - w0- t1 - iw1- f3 - - f5 -// -// f4 - - t0 - - f4 - w2- t0 -// f5 - w0- f5 - - f5 - w3- t1 -// f6 - - f6 - w1- f6 - iw2- f6 -// f7 - w0- t1 - iw1- f7 - iw3- f7 - - for (DiffUCnt = NDiffU; DiffUCnt > 0; DiffUCnt--) { - f0r = *p0r; - f0i = *(p0r + 1); - f1r = *p1r; - f1i = *(p1r + 1); - for (SameUCnt = NSameU - 1; SameUCnt > 0; SameUCnt--) { - f2r = *p2r; - f2i = *(p2r + 1); - f3r = *p3r; - f3i = *(p3r + 1); - - t0r = f0r + f1r * w0r + f1i * w0i; - t0i = f0i - f1r * w0i + f1i * w0r; - f1r = f0r * Two - t0r; - f1i = f0i * Two - t0i; - - f4r = *(p0r + pos); - f4i = *(p0r + posi); - f5r = *(p1r + pos); - f5i = *(p1r + posi); - - f6r = *(p2r + pos); - f6i = *(p2r + posi); - f7r = *(p3r + pos); - f7i = *(p3r + posi); - - t1r = f2r - f3r * w0r - f3i * w0i; - t1i = f2i + f3r * w0i - f3i * w0r; - f2r = f2r * Two - t1r; - f2i = f2i * Two - t1i; - - f0r = t0r + f2r * w1r + f2i * w1i; - f0i = t0i - f2r * w1i + f2i * w1r; - f2r = t0r * Two - f0r; - f2i = t0i * Two - f0i; - - f3r = f1r + t1r * w1i - t1i * w1r; - f3i = f1i + t1r * w1r + t1i * w1i; - f1r = f1r * Two - f3r; - f1i = f1i * Two - f3i; - - t0r = f4r + f5r * w0r + f5i * w0i; - t0i = f4i - f5r * w0i + f5i * w0r; - f5r = f4r * Two - t0r; - f5i = f4i * Two - t0i; - - t1r = f6r - f7r * w0r - f7i * w0i; - t1i = f6i + f7r * w0i - f7i * w0r; - f6r = f6r * Two - t1r; - f6i = f6i * Two - t1i; - - f4r = t0r + f6r * w1r + f6i * w1i; - f4i = t0i - f6r * w1i + f6i * w1r; - f6r = t0r * Two - f4r; - f6i = t0i * Two - f4i; - - f7r = f5r + t1r * w1i - t1i * w1r; - f7i = f5i + t1r * w1r + t1i * w1i; - f5r = f5r * Two - f7r; - f5i = f5i * Two - f7i; - - t0r = f0r - f4r * w2r - f4i * w2i; - t0i = f0i + f4r * w2i - f4i * w2r; - f0r = f0r * Two - t0r; - f0i = f0i * Two - t0i; - - t1r = f1r - f5r * w3r - f5i * w3i; - t1i = f1i + f5r * w3i - f5i * w3r; - f1r = f1r * Two - t1r; - f1i = f1i * Two - t1i; - - *(p0r + pos) = t0r; - *(p1r + pos) = t1r; - *(p0r + posi) = t0i; - *(p1r + posi) = t1i; - *p0r = f0r; - *p1r = f1r; - *(p0r + 1) = f0i; - *(p1r + 1) = f1i; - - p0r += pnext; - f0r = *p0r; - f0i = *(p0r + 1); - - p1r += pnext; - - f1r = *p1r; - f1i = *(p1r + 1); - - f4r = f2r - f6r * w2i + f6i * w2r; - f4i = f2i - f6r * w2r - f6i * w2i; - f6r = f2r * Two - f4r; - f6i = f2i * Two - f4i; - - f5r = f3r - f7r * w3i + f7i * w3r; - f5i = f3i - f7r * w3r - f7i * w3i; - f7r = f3r * Two - f5r; - f7i = f3i * Two - f5i; - - *p2r = f4r; - *p3r = f5r; - *(p2r + 1) = f4i; - *(p3r + 1) = f5i; - *(p2r + pos) = f6r; - *(p3r + pos) = f7r; - *(p2r + posi) = f6i; - *(p3r + posi) = f7i; - - p2r += pnext; - p3r += pnext; - } - - f2r = *p2r; - f2i = *(p2r + 1); - f3r = *p3r; - f3i = *(p3r + 1); - - t0r = f0r + f1r * w0r + f1i * w0i; - t0i = f0i - f1r * w0i + f1i * w0r; - f1r = f0r * Two - t0r; - f1i = f0i * Two - t0i; - - f4r = *(p0r + pos); - f4i = *(p0r + posi); - f5r = *(p1r + pos); - f5i = *(p1r + posi); - - f6r = *(p2r + pos); - f6i = *(p2r + posi); - f7r = *(p3r + pos); - f7i = *(p3r + posi); - - t1r = f2r - f3r * w0r - f3i * w0i; - t1i = f2i + f3r * w0i - f3i * w0r; - f2r = f2r * Two - t1r; - f2i = f2i * Two - t1i; - - f0r = t0r + f2r * w1r + f2i * w1i; - f0i = t0i - f2r * w1i + f2i * w1r; - f2r = t0r * Two - f0r; - f2i = t0i * Two - f0i; - - f3r = f1r + t1r * w1i - t1i * w1r; - f3i = f1i + t1r * w1r + t1i * w1i; - f1r = f1r * Two - f3r; - f1i = f1i * Two - f3i; - - if ((int) DiffUCnt == NDiffU / 2) - Uinc4 = -Uinc4; - - u0r += Uinc4; - u0i -= Uinc4; - u1r += Uinc2; - u1i -= Uinc2; - u2r += Uinc; - u2i -= Uinc; - - pstrt += 2; - - t0r = f4r + f5r * w0r + f5i * w0i; - t0i = f4i - f5r * w0i + f5i * w0r; - f5r = f4r * Two - t0r; - f5i = f4i * Two - t0i; - - t1r = f6r - f7r * w0r - f7i * w0i; - t1i = f6i + f7r * w0i - f7i * w0r; - f6r = f6r * Two - t1r; - f6i = f6i * Two - t1i; - - f4r = t0r + f6r * w1r + f6i * w1i; - f4i = t0i - f6r * w1i + f6i * w1r; - f6r = t0r * Two - f4r; - f6i = t0i * Two - f4i; - - f7r = f5r + t1r * w1i - t1i * w1r; - f7i = f5i + t1r * w1r + t1i * w1i; - f5r = f5r * Two - f7r; - f5i = f5i * Two - f7i; - - w0r = *u0r; - w0i = *u0i; - w1r = *u1r; - w1i = *u1i; - - if ((int) DiffUCnt <= NDiffU / 2) - w0r = -w0r; - - t0r = f0r - f4r * w2r - f4i * w2i; - t0i = f0i + f4r * w2i - f4i * w2r; - f0r = f0r * Two - t0r; - f0i = f0i * Two - t0i; - - f4r = f2r - f6r * w2i + f6i * w2r; - f4i = f2i - f6r * w2r - f6i * w2i; - f6r = f2r * Two - f4r; - f6i = f2i * Two - f4i; - - *(p0r + pos) = t0r; - *p2r = f4r; - *(p0r + posi) = t0i; - *(p2r + 1) = f4i; - w2r = *u2r; - w2i = *u2i; - *p0r = f0r; - *(p2r + pos) = f6r; - *(p0r + 1) = f0i; - *(p2r + posi) = f6i; - - p0r = pstrt; - p2r = pstrt + pinc + pinc; - - t1r = f1r - f5r * w3r - f5i * w3i; - t1i = f1i + f5r * w3i - f5i * w3r; - f1r = f1r * Two - t1r; - f1i = f1i * Two - t1i; - - f5r = f3r - f7r * w3i + f7i * w3r; - f5i = f3i - f7r * w3r - f7i * w3i; - f7r = f3r * Two - f5r; - f7i = f3i * Two - f5i; - - *(p1r + pos) = t1r; - *p3r = f5r; - *(p1r + posi) = t1i; - *(p3r + 1) = f5i; - w3r = *(u2r + U2toU3); - w3i = *(u2i - U2toU3); - *p1r = f1r; - *(p3r + pos) = f7r; - *(p1r + 1) = f1i; - *(p3r + posi) = f7i; - - p1r = pstrt + pinc; - p3r = p2r + pinc; - } - NSameU /= 8; - Uinc /= 8; - Uinc2 /= 8; - Uinc4 = Uinc * 4; - NDiffU *= 8; - pinc *= 8; - pnext *= 8; - pos *= 8; - posi = pos + 1; - } -} - -template -void g_fft::fftrecurs(FFT_TYPE *ioptr, int M, - FFT_TYPE *Utbl, int Ustride, int NDiffU, - int StageCnt) -{ -// recursive bfstages calls to maximize on chip cache efficiency - int i1; - - if (M <= (int) MCACHE) // fits on chip ? - bfstages(ioptr, M, Utbl, Ustride, NDiffU, StageCnt); // RADIX 8 Stages - else { - for (i1 = 0; i1 < 8; i1++) { - fftrecurs(&ioptr[i1 * POW2(M - 3) * 2], M - 3, Utbl, 8 * Ustride, - NDiffU, StageCnt - 1); // RADIX 8 Stages - } - bfstages(ioptr, M, Utbl, Ustride, POW2(M - 3), 1); // RADIX 8 Stage - } -} - -//------------------------------------------------------------------------------ -// Compute in-place complex fft on the rows of the input array -// INPUTS -// *ioptr = input data array -// M = log2 of fft size (ex M=10 for 1024 point fft) -// *Utbl = cosine table -// *BRLow = bit reversed counter table -// OUTPUTS -// *ioptr = output data array -//------------------------------------------------------------------------------ -template -void g_fft::ffts1(FFT_TYPE *ioptr, int M, FFT_TYPE *Utbl, short *BRLow) -{ - int StageCnt; - int NDiffU; - - switch (M) { - case 0: - break; - case 1: - fft2pt(ioptr); // a 2 pt fft - break; - case 2: - fft4pt(ioptr); // a 4 pt fft - break; - case 3: - fft8pt(ioptr); // an 8 pt fft - break; - default: - bitrevR2(ioptr, M, BRLow); // bit reverse and first radix 2 stage - StageCnt = (M - 1) / 3; // number of radix 8 stages - NDiffU = 2; // one radix 2 stage already complete - if ((M - 1 - (StageCnt * 3)) == 1) { - bfR2(ioptr, M, NDiffU); // 1 radix 2 stage - NDiffU *= 2; - } - if ((M - 1 - (StageCnt * 3)) == 2) { - bfR4(ioptr, M, NDiffU); // 1 radix 4 stage - NDiffU *= 4; - } - if (M <= (int) MCACHE) - bfstages(ioptr, M, Utbl, 1, NDiffU, StageCnt); // RADIX 8 Stages - else - fftrecurs(ioptr, M, Utbl, 1, NDiffU, StageCnt); // RADIX 8 Stages - } -} - -//------------------------------------------------------------------------------ -// parts of iffts1 -// scaled bit reverse and first radix 2 stage forward or inverse fft -//------------------------------------------------------------------------------ -template -void g_fft::scbitrevR2(FFT_TYPE *ioptr, int M, short *BRLow, FFT_TYPE scale) -{ - FFT_TYPE f0r; - FFT_TYPE f0i; - FFT_TYPE f1r; - FFT_TYPE f1i; - FFT_TYPE f2r; - FFT_TYPE f2i; - FFT_TYPE f3r; - FFT_TYPE f3i; - FFT_TYPE f4r; - FFT_TYPE f4i; - FFT_TYPE f5r; - FFT_TYPE f5i; - FFT_TYPE f6r; - FFT_TYPE f6i; - FFT_TYPE f7r; - FFT_TYPE f7i; - FFT_TYPE t0r; - FFT_TYPE t0i; - FFT_TYPE t1r; - FFT_TYPE t1i; - FFT_TYPE *p0r; - FFT_TYPE *p1r; - FFT_TYPE *IOP; - FFT_TYPE *iolimit; - int Colstart; - int iCol; - unsigned int posA; - unsigned int posAi; - unsigned int posB; - unsigned int posBi; - - const unsigned int Nrems2 = POW2((M + 3) / 2); - const unsigned int Nroot_1_ColInc = POW2(M) - Nrems2; - const unsigned int Nroot_1 = POW2(M / 2 - 1) - 1; - const unsigned int ColstartShift = (M + 1) / 2 + 1; - - posA = POW2(M); // 1/2 of POW2(M) complexes - posAi = posA + 1; - posB = posA + 2; - posBi = posB + 1; - - iolimit = ioptr + Nrems2; - for (; ioptr < iolimit; ioptr += POW2(M / 2 + 1)) { - for (Colstart = Nroot_1; Colstart >= 0; Colstart--) { - iCol = Nroot_1; - p0r = ioptr + Nroot_1_ColInc + BRLow[Colstart] * 4; - IOP = ioptr + (Colstart << ColstartShift); - p1r = IOP + BRLow[iCol] * 4; - f0r = *(p0r); - f0i = *(p0r + 1); - f1r = *(p0r + posA); - f1i = *(p0r + posAi); - for (; iCol > Colstart;) { - f2r = *(p0r + 2); - f2i = *(p0r + (2 + 1)); - f3r = *(p0r + posB); - f3i = *(p0r + posBi); - f4r = *(p1r); - f4i = *(p1r + 1); - f5r = *(p1r + posA); - f5i = *(p1r + posAi); - f6r = *(p1r + 2); - f6i = *(p1r + (2 + 1)); - f7r = *(p1r + posB); - f7i = *(p1r + posBi); - - t0r = f0r + f1r; - t0i = f0i + f1i; - f1r = f0r - f1r; - f1i = f0i - f1i; - t1r = f2r + f3r; - t1i = f2i + f3i; - f3r = f2r - f3r; - f3i = f2i - f3i; - f0r = f4r + f5r; - f0i = f4i + f5i; - f5r = f4r - f5r; - f5i = f4i - f5i; - f2r = f6r + f7r; - f2i = f6i + f7i; - f7r = f6r - f7r; - f7i = f6i - f7i; - - *(p1r) = scale * t0r; - *(p1r + 1) = scale * t0i; - *(p1r + 2) = scale * f1r; - *(p1r + (2 + 1)) = scale * f1i; - *(p1r + posA) = scale * t1r; - *(p1r + posAi) = scale * t1i; - *(p1r + posB) = scale * f3r; - *(p1r + posBi) = scale * f3i; - *(p0r) = scale * f0r; - *(p0r + 1) = scale * f0i; - *(p0r + 2) = scale * f5r; - *(p0r + (2 + 1)) = scale * f5i; - *(p0r + posA) = scale * f2r; - *(p0r + posAi) = scale * f2i; - *(p0r + posB) = scale * f7r; - *(p0r + posBi) = scale * f7i; - - p0r -= Nrems2; - f0r = *(p0r); - f0i = *(p0r + 1); - f1r = *(p0r + posA); - f1i = *(p0r + posAi); - iCol -= 1; - p1r = IOP + BRLow[iCol] * 4; - } - f2r = *(p0r + 2); - f2i = *(p0r + (2 + 1)); - f3r = *(p0r + posB); - f3i = *(p0r + posBi); - - t0r = f0r + f1r; - t0i = f0i + f1i; - f1r = f0r - f1r; - f1i = f0i - f1i; - t1r = f2r + f3r; - t1i = f2i + f3i; - f3r = f2r - f3r; - f3i = f2i - f3i; - - *(p0r) = scale * t0r; - *(p0r + 1) = scale * t0i; - *(p0r + 2) = scale * f1r; - *(p0r + (2 + 1)) = scale * f1i; - *(p0r + posA) = scale * t1r; - *(p0r + posAi) = scale * t1i; - *(p0r + posB) = scale * f3r; - *(p0r + posBi) = scale * f3i; - } - } -} - -//------------------------------------------------------------------------------ -// RADIX 2 ifft -//------------------------------------------------------------------------------ -template -void g_fft::ifft2pt(FFT_TYPE *ioptr, FFT_TYPE scale) -{ - FFT_TYPE f0r, f0i, f1r, f1i; - FFT_TYPE t0r, t0i; - -// bit reversed load - f0r = ioptr[0]; - f0i = ioptr[1]; - f1r = ioptr[2]; - f1i = ioptr[3]; - -// Butterflys -// f0 - - t0 -// f1 - 1 - f1 - - t0r = f0r + f1r; - t0i = f0i + f1i; - f1r = f0r - f1r; - f1i = f0i - f1i; - -// store result - ioptr[0] = scale * t0r; - ioptr[1] = scale * t0i; - ioptr[2] = scale * f1r; - ioptr[3] = scale * f1i; -} - -//------------------------------------------------------------------------------ -// RADIX 4 ifft -//------------------------------------------------------------------------------ -template -void g_fft::ifft4pt(FFT_TYPE *ioptr, FFT_TYPE scale) -{ - FFT_TYPE f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; - FFT_TYPE t0r, t0i, t1r, t1i; - -// bit reversed load - f0r = ioptr[0]; - f0i = ioptr[1]; - f1r = ioptr[4]; - f1i = ioptr[5]; - f2r = ioptr[2]; - f2i = ioptr[3]; - f3r = ioptr[6]; - f3i = ioptr[7]; - -// Butterflys -// f0 - - t0 - - f0 -// f1 - 1 - f1 - - f1 -// f2 - - f2 - 1 - f2 -// f3 - 1 - t1 - i - f3 - - t0r = f0r + f1r; - t0i = f0i + f1i; - f1r = f0r - f1r; - f1i = f0i - f1i; - - t1r = f2r - f3r; - t1i = f2i - f3i; - f2r = f2r + f3r; - f2i = f2i + f3i; - - f0r = t0r + f2r; - f0i = t0i + f2i; - f2r = t0r - f2r; - f2i = t0i - f2i; - - f3r = f1r + t1i; - f3i = f1i - t1r; - f1r = f1r - t1i; - f1i = f1i + t1r; - -// store result - ioptr[0] = scale * f0r; - ioptr[1] = scale * f0i; - ioptr[2] = scale * f1r; - ioptr[3] = scale * f1i; - ioptr[4] = scale * f2r; - ioptr[5] = scale * f2i; - ioptr[6] = scale * f3r; - ioptr[7] = scale * f3i; -} - -//------------------------------------------------------------------------------ -// RADIX 8 ifft -//------------------------------------------------------------------------------ -template -void g_fft::ifft8pt(FFT_TYPE *ioptr, FFT_TYPE scale) -{ - FFT_TYPE w0r = 1.0 / FFT_ROOT2; // cos(pi/4) - FFT_TYPE f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; - FFT_TYPE f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i; - FFT_TYPE t0r, t0i, t1r, t1i; - const FFT_TYPE Two = 2.0; - -// bit reversed load - f0r = ioptr[0]; - f0i = ioptr[1]; - f1r = ioptr[8]; - f1i = ioptr[9]; - f2r = ioptr[4]; - f2i = ioptr[5]; - f3r = ioptr[12]; - f3i = ioptr[13]; - f4r = ioptr[2]; - f4i = ioptr[3]; - f5r = ioptr[10]; - f5i = ioptr[11]; - f6r = ioptr[6]; - f6i = ioptr[7]; - f7r = ioptr[14]; - f7i = ioptr[15]; - -// Butterflys -// f0 - - t0 - - f0 - - f0 -// f1 - 1 - f1 - - f1 - - f1 -// f2 - - f2 - 1 - f2 - - f2 -// f3 - 1 - t1 - i - f3 - - f3 -// f4 - - t0 - - f4 - 1 - t0 -// f5 - 1 - f5 - - f5 - w3 - f4 -// f6 - - f6 - 1 - f6 - i - t1 -// f7 - 1 - t1 - i - f7 - iw3- f6 - - t0r = f0r + f1r; - t0i = f0i + f1i; - f1r = f0r - f1r; - f1i = f0i - f1i; - - t1r = f2r - f3r; - t1i = f2i - f3i; - f2r = f2r + f3r; - f2i = f2i + f3i; - - f0r = t0r + f2r; - f0i = t0i + f2i; - f2r = t0r - f2r; - f2i = t0i - f2i; - - f3r = f1r + t1i; - f3i = f1i - t1r; - f1r = f1r - t1i; - f1i = f1i + t1r; - - t0r = f4r + f5r; - t0i = f4i + f5i; - f5r = f4r - f5r; - f5i = f4i - f5i; - - t1r = f6r - f7r; - t1i = f6i - f7i; - f6r = f6r + f7r; - f6i = f6i + f7i; - - f4r = t0r + f6r; - f4i = t0i + f6i; - f6r = t0r - f6r; - f6i = t0i - f6i; - - f7r = f5r + t1i; - f7i = f5i - t1r; - f5r = f5r - t1i; - f5i = f5i + t1r; - - t0r = f0r - f4r; - t0i = f0i - f4i; - f0r = f0r + f4r; - f0i = f0i + f4i; - - t1r = f2r + f6i; - t1i = f2i - f6r; - f2r = f2r - f6i; - f2i = f2i + f6r; - - f4r = f1r - f5r * w0r + f5i * w0r; - f4i = f1i - f5r * w0r - f5i * w0r; - f1r = f1r * Two - f4r; - f1i = f1i * Two - f4i; - - f6r = f3r + f7r * w0r + f7i * w0r; - f6i = f3i - f7r * w0r + f7i * w0r; - f3r = f3r * Two - f6r; - f3i = f3i * Two - f6i; - -// store result - ioptr[0] = scale * f0r; - ioptr[1] = scale * f0i; - ioptr[2] = scale * f1r; - ioptr[3] = scale * f1i; - ioptr[4] = scale * f2r; - ioptr[5] = scale * f2i; - ioptr[6] = scale * f3r; - ioptr[7] = scale * f3i; - ioptr[8] = scale * t0r; - ioptr[9] = scale * t0i; - ioptr[10] = scale * f4r; - ioptr[11] = scale * f4i; - ioptr[12] = scale * t1r; - ioptr[13] = scale * t1i; - ioptr[14] = scale * f6r; - ioptr[15] = scale * f6i; -} - -//------------------------------------------------------------------------------ -// 2nd radix 2 stage -//------------------------------------------------------------------------------ -template -void g_fft::ibfR2(FFT_TYPE *ioptr, int M, int NDiffU) -{ - unsigned int pos; - unsigned int posi; - unsigned int pinc; - unsigned int pnext; - unsigned int NSameU; - unsigned int SameUCnt; - - FFT_TYPE *pstrt; - FFT_TYPE *p0r, *p1r, *p2r, *p3r; - - FFT_TYPE f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; - FFT_TYPE f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i; - - pinc = NDiffU * 2; // 2 floats per complex - pnext = pinc * 4; - pos = 2; - posi = pos + 1; - NSameU = POW2(M) / 4 / NDiffU; // 4 Us at a time - pstrt = ioptr; - p0r = pstrt; - p1r = pstrt + pinc; - p2r = p1r + pinc; - p3r = p2r + pinc; - -// Butterflys -// f0 - - f4 -// f1 - 1 - f5 -// f2 - - f6 -// f3 - 1 - f7 -// Butterflys -// f0 - - f4 -// f1 - 1 - f5 -// f2 - - f6 -// f3 - 1 - f7 - - for (SameUCnt = NSameU; SameUCnt > 0; SameUCnt--) { - - f0r = *p0r; - f1r = *p1r; - f0i = *(p0r + 1); - f1i = *(p1r + 1); - f2r = *p2r; - f3r = *p3r; - f2i = *(p2r + 1); - f3i = *(p3r + 1); - - f4r = f0r + f1r; - f4i = f0i + f1i; - f5r = f0r - f1r; - f5i = f0i - f1i; - - f6r = f2r + f3r; - f6i = f2i + f3i; - f7r = f2r - f3r; - f7i = f2i - f3i; - - *p0r = f4r; - *(p0r + 1) = f4i; - *p1r = f5r; - *(p1r + 1) = f5i; - *p2r = f6r; - *(p2r + 1) = f6i; - *p3r = f7r; - *(p3r + 1) = f7i; - - f0r = *(p0r + pos); - f1i = *(p1r + posi); - f0i = *(p0r + posi); - f1r = *(p1r + pos); - f2r = *(p2r + pos); - f3i = *(p3r + posi); - f2i = *(p2r + posi); - f3r = *(p3r + pos); - - f4r = f0r - f1i; - f4i = f0i + f1r; - f5r = f0r + f1i; - f5i = f0i - f1r; - - f6r = f2r - f3i; - f6i = f2i + f3r; - f7r = f2r + f3i; - f7i = f2i - f3r; - - *(p0r + pos) = f4r; - *(p0r + posi) = f4i; - *(p1r + pos) = f5r; - *(p1r + posi) = f5i; - *(p2r + pos) = f6r; - *(p2r + posi) = f6i; - *(p3r + pos) = f7r; - *(p3r + posi) = f7i; - - p0r += pnext; - p1r += pnext; - p2r += pnext; - p3r += pnext; - } -} - -//------------------------------------------------------------------------------ -// 1 radix 4 stage -//------------------------------------------------------------------------------ -template -void g_fft::ibfR4(FFT_TYPE *ioptr, int M, int NDiffU) -{ - unsigned int pos; - unsigned int posi; - unsigned int pinc; - unsigned int pnext; - unsigned int pnexti; - unsigned int NSameU; - unsigned int SameUCnt; - - FFT_TYPE *pstrt; - FFT_TYPE *p0r, *p1r, *p2r, *p3r; - - FFT_TYPE w1r = 1.0 / FFT_ROOT2; // cos(pi/4) - FFT_TYPE f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; - FFT_TYPE f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i; - FFT_TYPE t1r, t1i; - const FFT_TYPE Two = 2.0; - - pinc = NDiffU * 2; // 2 floats per complex - pnext = pinc * 4; - pnexti = pnext + 1; - pos = 2; - posi = pos + 1; - NSameU = POW2(M) / 4 / NDiffU; // 4 pts per butterfly - pstrt = ioptr; - p0r = pstrt; - p1r = pstrt + pinc; - p2r = p1r + pinc; - p3r = p2r + pinc; - -// Butterflys -// f0 - - f0 - - f4 -// f1 - 1 - f5 - - f5 -// f2 - - f6 - 1 - f6 -// f3 - 1 - f3 - -i - f7 -// Butterflys -// f0 - - f4 - - f4 -// f1 - -i - t1 - - f5 -// f2 - - f2 - w1 - f6 -// f3 - -i - f7 - iw1- f7 - - f0r = *p0r; - f1r = *p1r; - f2r = *p2r; - f3r = *p3r; - f0i = *(p0r + 1); - f1i = *(p1r + 1); - f2i = *(p2r + 1); - f3i = *(p3r + 1); - - f5r = f0r - f1r; - f5i = f0i - f1i; - f0r = f0r + f1r; - f0i = f0i + f1i; - - f6r = f2r + f3r; - f6i = f2i + f3i; - f3r = f2r - f3r; - f3i = f2i - f3i; - - for (SameUCnt = NSameU - 1; SameUCnt > 0; SameUCnt--) { - - f7r = f5r + f3i; - f7i = f5i - f3r; - f5r = f5r - f3i; - f5i = f5i + f3r; - - f4r = f0r + f6r; - f4i = f0i + f6i; - f6r = f0r - f6r; - f6i = f0i - f6i; - - f2r = *(p2r + pos); - f2i = *(p2r + posi); - f1r = *(p1r + pos); - f1i = *(p1r + posi); - f3i = *(p3r + posi); - f0r = *(p0r + pos); - f3r = *(p3r + pos); - f0i = *(p0r + posi); - - *p3r = f7r; - *p0r = f4r; - *(p3r + 1) = f7i; - *(p0r + 1) = f4i; - *p1r = f5r; - *p2r = f6r; - *(p1r + 1) = f5i; - *(p2r + 1) = f6i; - - f7r = f2r + f3i; - f7i = f2i - f3r; - f2r = f2r - f3i; - f2i = f2i + f3r; - - f4r = f0r - f1i; - f4i = f0i + f1r; - t1r = f0r + f1i; - t1i = f0i - f1r; - - f5r = t1r - f7r * w1r - f7i * w1r; - f5i = t1i + f7r * w1r - f7i * w1r; - f7r = t1r * Two - f5r; - f7i = t1i * Two - f5i; - - f6r = f4r - f2r * w1r + f2i * w1r; - f6i = f4i - f2r * w1r - f2i * w1r; - f4r = f4r * Two - f6r; - f4i = f4i * Two - f6i; - - f3r = *(p3r + pnext); - f0r = *(p0r + pnext); - f3i = *(p3r + pnexti); - f0i = *(p0r + pnexti); - f2r = *(p2r + pnext); - f2i = *(p2r + pnexti); - f1r = *(p1r + pnext); - f1i = *(p1r + pnexti); - - *(p2r + pos) = f6r; - *(p1r + pos) = f5r; - *(p2r + posi) = f6i; - *(p1r + posi) = f5i; - *(p3r + pos) = f7r; - *(p0r + pos) = f4r; - *(p3r + posi) = f7i; - *(p0r + posi) = f4i; - - f6r = f2r + f3r; - f6i = f2i + f3i; - f3r = f2r - f3r; - f3i = f2i - f3i; - - f5r = f0r - f1r; - f5i = f0i - f1i; - f0r = f0r + f1r; - f0i = f0i + f1i; - - p3r += pnext; - p0r += pnext; - p1r += pnext; - p2r += pnext; - } - f7r = f5r + f3i; - f7i = f5i - f3r; - f5r = f5r - f3i; - f5i = f5i + f3r; - - f4r = f0r + f6r; - f4i = f0i + f6i; - f6r = f0r - f6r; - f6i = f0i - f6i; - - f2r = *(p2r + pos); - f2i = *(p2r + posi); - f1r = *(p1r + pos); - f1i = *(p1r + posi); - f3i = *(p3r + posi); - f0r = *(p0r + pos); - f3r = *(p3r + pos); - f0i = *(p0r + posi); - - *p3r = f7r; - *p0r = f4r; - *(p3r + 1) = f7i; - *(p0r + 1) = f4i; - *p1r = f5r; - *p2r = f6r; - *(p1r + 1) = f5i; - *(p2r + 1) = f6i; - - f7r = f2r + f3i; - f7i = f2i - f3r; - f2r = f2r - f3i; - f2i = f2i + f3r; - - f4r = f0r - f1i; - f4i = f0i + f1r; - t1r = f0r + f1i; - t1i = f0i - f1r; - - f5r = t1r - f7r * w1r - f7i * w1r; - f5i = t1i + f7r * w1r - f7i * w1r; - f7r = t1r * Two - f5r; - f7i = t1i * Two - f5i; - - f6r = f4r - f2r * w1r + f2i * w1r; - f6i = f4i - f2r * w1r - f2i * w1r; - f4r = f4r * Two - f6r; - f4i = f4i * Two - f6i; - - *(p2r + pos) = f6r; - *(p1r + pos) = f5r; - *(p2r + posi) = f6i; - *(p1r + posi) = f5i; - *(p3r + pos) = f7r; - *(p0r + pos) = f4r; - *(p3r + posi) = f7i; - *(p0r + posi) = f4i; -} - -//------------------------------------------------------------------------------ -// RADIX 8 Stages -//------------------------------------------------------------------------------ -template -void g_fft::ibfstages(FFT_TYPE *ioptr, int M, FFT_TYPE *Utbl, int Ustride, - int NDiffU, int StageCnt) -{ - unsigned int pos; - unsigned int posi; - unsigned int pinc; - unsigned int pnext; - unsigned int NSameU; - int Uinc; - int Uinc2; - int Uinc4; - unsigned int DiffUCnt; - unsigned int SameUCnt; - unsigned int U2toU3; - - FFT_TYPE *pstrt; - FFT_TYPE *p0r, *p1r, *p2r, *p3r; - FFT_TYPE *u0r, *u0i, *u1r, *u1i, *u2r, *u2i; - - FFT_TYPE w0r, w0i, w1r, w1i, w2r, w2i, w3r, w3i; - FFT_TYPE f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; - FFT_TYPE f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i; - FFT_TYPE t0r, t0i, t1r, t1i; - const FFT_TYPE Two = 2.0; - - pinc = NDiffU * 2; // 2 floats per complex - pnext = pinc * 8; - pos = pinc * 4; - posi = pos + 1; - NSameU = POW2(M) / 8 / NDiffU; // 8 pts per butterfly - Uinc = (int) NSameU * Ustride; - Uinc2 = Uinc * 2; - Uinc4 = Uinc * 4; - U2toU3 = (POW2(M) / 8) * Ustride; - for (; StageCnt > 0; StageCnt--) { - - u0r = &Utbl[0]; - u0i = &Utbl[POW2(M - 2) * Ustride]; - u1r = u0r; - u1i = u0i; - u2r = u0r; - u2i = u0i; - - w0r = *u0r; - w0i = *u0i; - w1r = *u1r; - w1i = *u1i; - w2r = *u2r; - w2i = *u2i; - w3r = *(u2r + U2toU3); - w3i = *(u2i - U2toU3); - - pstrt = ioptr; - - p0r = pstrt; - p1r = pstrt + pinc; - p2r = p1r + pinc; - p3r = p2r + pinc; - -// Butterflys -// f0 - - t0 - - f0 - - f0 -// f1 - w0- f1 - - f1 - - f1 -// f2 - - f2 - w1- f2 - - f4 -// f3 - w0- t1 - iw1- f3 - - f5 -// f4 - - t0 - - f4 - w2- t0 -// f5 - w0- f5 - - f5 - w3- t1 -// f6 - - f6 - w1- f6 - iw2- f6 -// f7 - w0- t1 - iw1- f7 - iw3- f7 - - for (DiffUCnt = NDiffU; DiffUCnt > 0; DiffUCnt--) { - f0r = *p0r; - f0i = *(p0r + 1); - f1r = *p1r; - f1i = *(p1r + 1); - for (SameUCnt = NSameU - 1; SameUCnt > 0; SameUCnt--) { - f2r = *p2r; - f2i = *(p2r + 1); - f3r = *p3r; - f3i = *(p3r + 1); - - t0r = f0r + f1r * w0r - f1i * w0i; - t0i = f0i + f1r * w0i + f1i * w0r; - f1r = f0r * Two - t0r; - f1i = f0i * Two - t0i; - - f4r = *(p0r + pos); - f4i = *(p0r + posi); - f5r = *(p1r + pos); - f5i = *(p1r + posi); - - f6r = *(p2r + pos); - f6i = *(p2r + posi); - f7r = *(p3r + pos); - f7i = *(p3r + posi); - - t1r = f2r - f3r * w0r + f3i * w0i; - t1i = f2i - f3r * w0i - f3i * w0r; - f2r = f2r * Two - t1r; - f2i = f2i * Two - t1i; - - f0r = t0r + f2r * w1r - f2i * w1i; - f0i = t0i + f2r * w1i + f2i * w1r; - f2r = t0r * Two - f0r; - f2i = t0i * Two - f0i; - - f3r = f1r + t1r * w1i + t1i * w1r; - f3i = f1i - t1r * w1r + t1i * w1i; - f1r = f1r * Two - f3r; - f1i = f1i * Two - f3i; - - t0r = f4r + f5r * w0r - f5i * w0i; - t0i = f4i + f5r * w0i + f5i * w0r; - f5r = f4r * Two - t0r; - f5i = f4i * Two - t0i; - - t1r = f6r - f7r * w0r + f7i * w0i; - t1i = f6i - f7r * w0i - f7i * w0r; - f6r = f6r * Two - t1r; - f6i = f6i * Two - t1i; - - f4r = t0r + f6r * w1r - f6i * w1i; - f4i = t0i + f6r * w1i + f6i * w1r; - f6r = t0r * Two - f4r; - f6i = t0i * Two - f4i; - - f7r = f5r + t1r * w1i + t1i * w1r; - f7i = f5i - t1r * w1r + t1i * w1i; - f5r = f5r * Two - f7r; - f5i = f5i * Two - f7i; - - t0r = f0r - f4r * w2r + f4i * w2i; - t0i = f0i - f4r * w2i - f4i * w2r; - f0r = f0r * Two - t0r; - f0i = f0i * Two - t0i; - - t1r = f1r - f5r * w3r + f5i * w3i; - t1i = f1i - f5r * w3i - f5i * w3r; - f1r = f1r * Two - t1r; - f1i = f1i * Two - t1i; - - *(p0r + pos) = t0r; - *(p0r + posi) = t0i; - *p0r = f0r; - *(p0r + 1) = f0i; - - p0r += pnext; - f0r = *p0r; - f0i = *(p0r + 1); - - *(p1r + pos) = t1r; - *(p1r + posi) = t1i; - *p1r = f1r; - *(p1r + 1) = f1i; - - p1r += pnext; - - f1r = *p1r; - f1i = *(p1r + 1); - - f4r = f2r - f6r * w2i - f6i * w2r; - f4i = f2i + f6r * w2r - f6i * w2i; - f6r = f2r * Two - f4r; - f6i = f2i * Two - f4i; - - f5r = f3r - f7r * w3i - f7i * w3r; - f5i = f3i + f7r * w3r - f7i * w3i; - f7r = f3r * Two - f5r; - f7i = f3i * Two - f5i; - - *p2r = f4r; - *(p2r + 1) = f4i; - *(p2r + pos) = f6r; - *(p2r + posi) = f6i; - - p2r += pnext; - - *p3r = f5r; - *(p3r + 1) = f5i; - *(p3r + pos) = f7r; - *(p3r + posi) = f7i; - - p3r += pnext; - } - - f2r = *p2r; - f2i = *(p2r + 1); - f3r = *p3r; - f3i = *(p3r + 1); - - t0r = f0r + f1r * w0r - f1i * w0i; - t0i = f0i + f1r * w0i + f1i * w0r; - f1r = f0r * Two - t0r; - f1i = f0i * Two - t0i; - - f4r = *(p0r + pos); - f4i = *(p0r + posi); - f5r = *(p1r + pos); - f5i = *(p1r + posi); - - f6r = *(p2r + pos); - f6i = *(p2r + posi); - f7r = *(p3r + pos); - f7i = *(p3r + posi); - - t1r = f2r - f3r * w0r + f3i * w0i; - t1i = f2i - f3r * w0i - f3i * w0r; - f2r = f2r * Two - t1r; - f2i = f2i * Two - t1i; - - f0r = t0r + f2r * w1r - f2i * w1i; - f0i = t0i + f2r * w1i + f2i * w1r; - f2r = t0r * Two - f0r; - f2i = t0i * Two - f0i; - - f3r = f1r + t1r * w1i + t1i * w1r; - f3i = f1i - t1r * w1r + t1i * w1i; - f1r = f1r * Two - f3r; - f1i = f1i * Two - f3i; - - if ((int) DiffUCnt == NDiffU / 2) - Uinc4 = -Uinc4; - - u0r += Uinc4; - u0i -= Uinc4; - u1r += Uinc2; - u1i -= Uinc2; - u2r += Uinc; - u2i -= Uinc; - - pstrt += 2; - - t0r = f4r + f5r * w0r - f5i * w0i; - t0i = f4i + f5r * w0i + f5i * w0r; - f5r = f4r * Two - t0r; - f5i = f4i * Two - t0i; - - t1r = f6r - f7r * w0r + f7i * w0i; - t1i = f6i - f7r * w0i - f7i * w0r; - f6r = f6r * Two - t1r; - f6i = f6i * Two - t1i; - - f4r = t0r + f6r * w1r - f6i * w1i; - f4i = t0i + f6r * w1i + f6i * w1r; - f6r = t0r * Two - f4r; - f6i = t0i * Two - f4i; - - f7r = f5r + t1r * w1i + t1i * w1r; - f7i = f5i - t1r * w1r + t1i * w1i; - f5r = f5r * Two - f7r; - f5i = f5i * Two - f7i; - - w0r = *u0r; - w0i = *u0i; - w1r = *u1r; - w1i = *u1i; - - if ((int) DiffUCnt <= NDiffU / 2) - w0r = -w0r; - - t0r = f0r - f4r * w2r + f4i * w2i; - t0i = f0i - f4r * w2i - f4i * w2r; - f0r = f0r * Two - t0r; - f0i = f0i * Two - t0i; - - f4r = f2r - f6r * w2i - f6i * w2r; - f4i = f2i + f6r * w2r - f6i * w2i; - f6r = f2r * Two - f4r; - f6i = f2i * Two - f4i; - - *(p0r + pos) = t0r; - *p2r = f4r; - *(p0r + posi) = t0i; - *(p2r + 1) = f4i; - w2r = *u2r; - w2i = *u2i; - *p0r = f0r; - *(p2r + pos) = f6r; - *(p0r + 1) = f0i; - *(p2r + posi) = f6i; - - p0r = pstrt; - p2r = pstrt + pinc + pinc; - - t1r = f1r - f5r * w3r + f5i * w3i; - t1i = f1i - f5r * w3i - f5i * w3r; - f1r = f1r * Two - t1r; - f1i = f1i * Two - t1i; - - f5r = f3r - f7r * w3i - f7i * w3r; - f5i = f3i + f7r * w3r - f7i * w3i; - f7r = f3r * Two - f5r; - f7i = f3i * Two - f5i; - - *(p1r + pos) = t1r; - *p3r = f5r; - *(p1r + posi) = t1i; - *(p3r + 1) = f5i; - w3r = *(u2r + U2toU3); - w3i = *(u2i - U2toU3); - *p1r = f1r; - *(p3r + pos) = f7r; - *(p1r + 1) = f1i; - *(p3r + posi) = f7i; - - p1r = pstrt + pinc; - p3r = p2r + pinc; - } - NSameU /= 8; - Uinc /= 8; - Uinc2 /= 8; - Uinc4 = Uinc * 4; - NDiffU *= 8; - pinc *= 8; - pnext *= 8; - pos *= 8; - posi = pos + 1; - } -} - -//------------------------------------------------------------------------------ -// recursive bfstages calls to maximize on chip cache efficiency -//------------------------------------------------------------------------------ -template -void g_fft::ifftrecurs(FFT_TYPE *ioptr, int M, FFT_TYPE *Utbl, int Ustride, - int NDiffU, int StageCnt) -{ - int i1; - - if (M <= (int) MCACHE) - ibfstages(ioptr, M, Utbl, Ustride, NDiffU, StageCnt); // RADIX 8 Stages - else { - for (i1 = 0; i1 < 8; i1++) { - ifftrecurs(&ioptr[i1 * POW2(M - 3) * 2], M - 3, Utbl, 8 * Ustride, - NDiffU, StageCnt - 1); // RADIX 8 Stages - } - ibfstages(ioptr, M, Utbl, Ustride, POW2(M - 3), 1); // RADIX 8 Stage - } -} - -//------------------------------------------------------------------------------ -// Compute in-place inverse complex fft on the rows of the input array -// INPUTS -// *ioptr = input data array -// M = log2 of fft size -// *Utbl = cosine table -// *BRLow = bit reversed counter table -// OUTPUTS -// *ioptr = output data array -//------------------------------------------------------------------------------ -template -void g_fft::iffts1(FFT_TYPE *ioptr, int M, FFT_TYPE *Utbl, short *BRLow) -{ - int StageCnt; - int NDiffU; - const FFT_TYPE scale = 1.0 / POW2(M); - - switch (M) { - case 0: - break; - case 1: - ifft2pt(ioptr, scale); // a 2 pt fft - break; - case 2: - ifft4pt(ioptr, scale); // a 4 pt fft - break; - case 3: - ifft8pt(ioptr, scale); // an 8 pt fft - break; - default: -// bit reverse and first radix 2 stage - scbitrevR2(ioptr, M, BRLow, scale); - StageCnt = (M - 1) / 3; // number of radix 8 stages - NDiffU = 2; // one radix 2 stage already complete - if ((M - 1 - (StageCnt * 3)) == 1) { - ibfR2(ioptr, M, NDiffU); // 1 radix 2 stage - NDiffU *= 2; - } - if ((M - 1 - (StageCnt * 3)) == 2) { - ibfR4(ioptr, M, NDiffU); // 1 radix 4 stage - NDiffU *= 4; - } - if (M <= (int) MCACHE) - ibfstages(ioptr, M, Utbl, 1, NDiffU, StageCnt); // RADIX 8 Stages - else - ifftrecurs(ioptr, M, Utbl, 1, NDiffU, StageCnt); // RADIX 8 Stages - } -} - -//------------------------------------------------------------------------------ -// parts of rffts1 -// RADIX 2 rfft -//------------------------------------------------------------------------------ -template -void g_fft::rfft1pt(FFT_TYPE *ioptr) -{ - FFT_TYPE f0r, f0i; - FFT_TYPE t0r, t0i; - -// bit reversed load - f0r = ioptr[0]; - f0i = ioptr[1]; - -// finish rfft - t0r = f0r + f0i; - t0i = f0r - f0i; - -// store result - ioptr[0] = t0r; - ioptr[1] = t0i; -} - -//------------------------------------------------------------------------------ -// RADIX 4 rfft -//------------------------------------------------------------------------------ -template -void g_fft::rfft2pt(FFT_TYPE *ioptr) -{ - FFT_TYPE f0r, f0i, f1r, f1i; - FFT_TYPE t0r, t0i; - -// bit reversed load - f0r = ioptr[0]; - f0i = ioptr[1]; - f1r = ioptr[2]; - f1i = ioptr[3]; - -// Butterflys -// f0 - - t0 -// f1 - 1 - f1 - - t0r = f0r + f1r; - t0i = f0i + f1i; - f1r = f0r - f1r; - f1i = f1i - f0i; -// finish rfft - f0r = t0r + t0i; - f0i = t0r - t0i; - -// store result - ioptr[0] = f0r; - ioptr[1] = f0i; - ioptr[2] = f1r; - ioptr[3] = f1i; -} - -//------------------------------------------------------------------------------ -// RADIX 8 rfft -//------------------------------------------------------------------------------ -template -void g_fft::rfft4pt(FFT_TYPE *ioptr) -{ - FFT_TYPE f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; - FFT_TYPE t0r, t0i, t1r, t1i; - FFT_TYPE w0r = 1.0 / FFT_ROOT2; // cos(pi/4) - const FFT_TYPE Two = 2.0; - const FFT_TYPE scale = 0.5; - -// bit reversed load - f0r = ioptr[0]; - f0i = ioptr[1]; - f1r = ioptr[4]; - f1i = ioptr[5]; - f2r = ioptr[2]; - f2i = ioptr[3]; - f3r = ioptr[6]; - f3i = ioptr[7]; - -// Butterflys -// f0 - - t0 - - f0 -// f1 - 1 - f1 - - f1 -// f2 - - f2 - 1 - f2 -// f3 - 1 - t1 - -i - f3 - - t0r = f0r + f1r; - t0i = f0i + f1i; - f1r = f0r - f1r; - f1i = f0i - f1i; - - t1r = f2r - f3r; - t1i = f2i - f3i; - f2r = f2r + f3r; - f2i = f2i + f3i; - - f0r = t0r + f2r; - f0i = t0i + f2i; - f2r = t0r - f2r; - f2i = f2i - t0i; // neg for rfft - - f3r = f1r - t1i; - f3i = f1i + t1r; - f1r = f1r + t1i; - f1i = f1i - t1r; - -// finish rfft - t0r = f0r + f0i; // compute Re(x[0]) - t0i = f0r - f0i; // compute Re(x[N/2]) - - t1r = f1r + f3r; - t1i = f1i - f3i; - f0r = f1i + f3i; - f0i = f3r - f1r; - - f1r = t1r + w0r * f0r + w0r * f0i; - f1i = t1i - w0r * f0r + w0r * f0i; - f3r = Two * t1r - f1r; - f3i = f1i - Two * t1i; - -// store result - ioptr[4] = f2r; - ioptr[5] = f2i; - ioptr[0] = t0r; - ioptr[1] = t0i; - - ioptr[2] = scale * f1r; - ioptr[3] = scale * f1i; - ioptr[6] = scale * f3r; - ioptr[7] = scale * f3i; -} - -//------------------------------------------------------------------------------ -// RADIX 16 rfft -//------------------------------------------------------------------------------ -template -void g_fft::rfft8pt(FFT_TYPE *ioptr) -{ - FFT_TYPE w0r = 1.0 / FFT_ROOT2; // cos(pi/4) - FFT_TYPE w1r = FFT_COSPID8; // cos(pi/8) - FFT_TYPE w1i = FFT_SINPID8; // sin(pi/8) - FFT_TYPE f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; - FFT_TYPE f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i; - FFT_TYPE t0r, t0i, t1r, t1i; - const FFT_TYPE Two = 2.0; - const FFT_TYPE scale = 0.5; - -// bit reversed load - f0r = ioptr[0]; - f0i = ioptr[1]; - f1r = ioptr[8]; - f1i = ioptr[9]; - f2r = ioptr[4]; - f2i = ioptr[5]; - f3r = ioptr[12]; - f3i = ioptr[13]; - f4r = ioptr[2]; - f4i = ioptr[3]; - f5r = ioptr[10]; - f5i = ioptr[11]; - f6r = ioptr[6]; - f6i = ioptr[7]; - f7r = ioptr[14]; - f7i = ioptr[15]; - -// Butterflys -// f0 - - t0 - - f0 - - f0 -// f1 - 1 - f1 - - f1 - - f1 -// f2 - - f2 - 1 - f2 - - f2 -// f3 - 1 - t1 - -i - f3 - - f3 -// f4 - - t0 - - f4 - 1 - t0 -// f5 - 1 - f5 - - f5 - w3 - f4 -// f6 - - f6 - 1 - f6 - -i - t1 -// f7 - 1 - t1 - -i - f7 - iw3- f6 - - t0r = f0r + f1r; - t0i = f0i + f1i; - f1r = f0r - f1r; - f1i = f0i - f1i; - - t1r = f2r - f3r; - t1i = f2i - f3i; - f2r = f2r + f3r; - f2i = f2i + f3i; - - f0r = t0r + f2r; - f0i = t0i + f2i; - f2r = t0r - f2r; - f2i = t0i - f2i; - - f3r = f1r - t1i; - f3i = f1i + t1r; - f1r = f1r + t1i; - f1i = f1i - t1r; - - t0r = f4r + f5r; - t0i = f4i + f5i; - f5r = f4r - f5r; - f5i = f4i - f5i; - - t1r = f6r - f7r; - t1i = f6i - f7i; - f6r = f6r + f7r; - f6i = f6i + f7i; - - f4r = t0r + f6r; - f4i = t0i + f6i; - f6r = t0r - f6r; - f6i = t0i - f6i; - - f7r = f5r - t1i; - f7i = f5i + t1r; - f5r = f5r + t1i; - f5i = f5i - t1r; - - t0r = f0r - f4r; - t0i = f4i - f0i; // neg for rfft - f0r = f0r + f4r; - f0i = f0i + f4i; - - t1r = f2r - f6i; - t1i = f2i + f6r; - f2r = f2r + f6i; - f2i = f2i - f6r; - - f4r = f1r - f5r * w0r - f5i * w0r; - f4i = f1i + f5r * w0r - f5i * w0r; - f1r = f1r * Two - f4r; - f1i = f1i * Two - f4i; - - f6r = f3r + f7r * w0r - f7i * w0r; - f6i = f3i + f7r * w0r + f7i * w0r; - f3r = f3r * Two - f6r; - f3i = f3i * Two - f6i; - -// finish rfft - f5r = f0r + f0i; // compute Re(x[0]) - f5i = f0r - f0i; // compute Re(x[N/2]) - - f0r = f2r + t1r; - f0i = f2i - t1i; - f7r = f2i + t1i; - f7i = t1r - f2r; - - f2r = f0r + w0r * f7r + w0r * f7i; - f2i = f0i - w0r * f7r + w0r * f7i; - t1r = Two * f0r - f2r; - t1i = f2i - Two * f0i; - - f0r = f1r + f6r; - f0i = f1i - f6i; - f7r = f1i + f6i; - f7i = f6r - f1r; - - f1r = f0r + w1r * f7r + w1i * f7i; - f1i = f0i - w1i * f7r + w1r * f7i; - f6r = Two * f0r - f1r; - f6i = f1i - Two * f0i; - - f0r = f3r + f4r; - f0i = f3i - f4i; - f7r = f3i + f4i; - f7i = f4r - f3r; - - f3r = f0r + w1i * f7r + w1r * f7i; - f3i = f0i - w1r * f7r + w1i * f7i; - f4r = Two * f0r - f3r; - f4i = f3i - Two * f0i; - -// store result - ioptr[8] = t0r; - ioptr[9] = t0i; - ioptr[0] = f5r; - ioptr[1] = f5i; - - ioptr[4] = scale * f2r; - ioptr[5] = scale * f2i; - ioptr[12] = scale * t1r; - ioptr[13] = scale * t1i; - - ioptr[2] = scale * f1r; - ioptr[3] = scale * f1i; - ioptr[6] = scale * f3r; - ioptr[7] = scale * f3i; - ioptr[10] = scale * f4r; - ioptr[11] = scale * f4i; - ioptr[14] = scale * f6r; - ioptr[15] = scale * f6i; -} - -//------------------------------------------------------------------------------ -// Finish RFFT -//------------------------------------------------------------------------------ -template -void g_fft::frstage(FFT_TYPE *ioptr, int M, FFT_TYPE *Utbl) -{ - unsigned int pos; - unsigned int posi; - unsigned int diffUcnt; - - FFT_TYPE *p0r, *p1r; - FFT_TYPE *u0r, *u0i; - - FFT_TYPE w0r, w0i; - FFT_TYPE f0r, f0i, f1r, f1i, f4r, f4i, f5r, f5i; - FFT_TYPE t0r, t0i, t1r, t1i; - const FFT_TYPE Two = 2.0; - - pos = POW2(M - 1); - posi = pos + 1; - - p0r = ioptr; - p1r = ioptr + pos / 2; - - u0r = Utbl + POW2(M - 3); - - w0r = *u0r, f0r = *(p0r); - f0i = *(p0r + 1); - f4r = *(p0r + pos); - f4i = *(p0r + posi); - f1r = *(p1r); - f1i = *(p1r + 1); - f5r = *(p1r + pos); - f5i = *(p1r + posi); - - t0r = Two * f0r + Two * f0i; // compute Re(x[0]) - t0i = Two * f0r - Two * f0i; // compute Re(x[N/2]) - t1r = f4r + f4r; - t1i = -f4i - f4i; - - f0r = f1r + f5r; - f0i = f1i - f5i; - f4r = f1i + f5i; - f4i = f5r - f1r; - - f1r = f0r + w0r * f4r + w0r * f4i; - f1i = f0i - w0r * f4r + w0r * f4i; - f5r = Two * f0r - f1r; - f5i = f1i - Two * f0i; - - *(p0r) = t0r; - *(p0r + 1) = t0i; - *(p0r + pos) = t1r; - *(p0r + posi) = t1i; - *(p1r) = f1r; - *(p1r + 1) = f1i; - *(p1r + pos) = f5r; - *(p1r + posi) = f5i; - - u0r = Utbl + 1; - u0i = Utbl + (POW2(M - 2) - 1); - - w0r = *u0r, w0i = *u0i; - - p0r = (ioptr + 2); - p1r = (ioptr + (POW2(M - 2) - 1) * 2); - -// Butterflys -// f0 - t0 - - f0 -// f5 - t1 - w0 - f5 -// f1 - t0 - - f1 -// f4 - t1 -iw0 - f4 - - for (diffUcnt = POW2(M - 3) - 1; diffUcnt > 0; diffUcnt--) { - - f0r = *(p0r); - f0i = *(p0r + 1); - f5r = *(p1r + pos); - f5i = *(p1r + posi); - f1r = *(p1r); - f1i = *(p1r + 1); - f4r = *(p0r + pos); - f4i = *(p0r + posi); - - t0r = f0r + f5r; - t0i = f0i - f5i; - t1r = f0i + f5i; - t1i = f5r - f0r; - - f0r = t0r + w0r * t1r + w0i * t1i; - f0i = t0i - w0i * t1r + w0r * t1i; - f5r = Two * t0r - f0r; - f5i = f0i - Two * t0i; - - t0r = f1r + f4r; - t0i = f1i - f4i; - t1r = f1i + f4i; - t1i = f4r - f1r; - - f1r = t0r + w0i * t1r + w0r * t1i; - f1i = t0i - w0r * t1r + w0i * t1i; - f4r = Two * t0r - f1r; - f4i = f1i - Two * t0i; - - *(p0r) = f0r; - *(p0r + 1) = f0i; - *(p1r + pos) = f5r; - *(p1r + posi) = f5i; - - w0r = *++u0r; - w0i = *--u0i; - - *(p1r) = f1r; - *(p1r + 1) = f1i; - *(p0r + pos) = f4r; - *(p0r + posi) = f4i; - - p0r += 2; - p1r -= 2; - } -} - -//------------------------------------------------------------------------------ -// Compute in-place real fft on the rows of the input array -// The result is the complex spectra of the positive frequencies -// except the location for the first complex number contains the real -// values for DC and Nyquest -// INPUTS -// *ioptr = real input data array -// M = log2 of fft size -// *Utbl = cosine table -// *BRLow = bit reversed counter table -// OUTPUTS -// *ioptr = output data array in the following order -// Re(x[0]), Re(x[N/2]), Re(x[1]), Im(x[1]), Re(x[2]), Im(x[2]), -// ... Re(x[N/2-1]), Im(x[N/2-1]). -//------------------------------------------------------------------------------ -template -void g_fft::rffts1(FFT_TYPE *ioptr, int M, FFT_TYPE *Utbl, short *BRLow) -{ - FFT_TYPE scale; - int StageCnt; - int NDiffU; - - M = M - 1; - switch (M) { - case -1: - break; - case 0: - rfft1pt(ioptr); // a 2 pt fft - break; - case 1: - rfft2pt(ioptr); // a 4 pt fft - break; - case 2: - rfft4pt(ioptr); // an 8 pt fft - break; - case 3: - rfft8pt(ioptr); // a 16 pt fft - break; - default: - scale = 0.5; -// bit reverse and first radix 2 stage - scbitrevR2(ioptr, M, BRLow, scale); - StageCnt = (M - 1) / 3; // number of radix 8 stages - NDiffU = 2; // one radix 2 stage already complete - if ((M - 1 - (StageCnt * 3)) == 1) { - bfR2(ioptr, M, NDiffU); // 1 radix 2 stage - NDiffU *= 2; - } - if ((M - 1 - (StageCnt * 3)) == 2) { - bfR4(ioptr, M, NDiffU); // 1 radix 4 stage - NDiffU *= 4; - } - if (M <= (int) MCACHE) - bfstages(ioptr, M, Utbl, 2, NDiffU, StageCnt); // RADIX 8 Stages - else - fftrecurs(ioptr, M, Utbl, 2, NDiffU, StageCnt); // RADIX 8 Stages - frstage(ioptr, M + 1, Utbl); - } -} - -//------------------------------------------------------------------------------ -// parts of riffts1 -//------------------------------------------------------------------------------ - -//------------------------------------------------------------------------------ -// RADIX 2 rifft -//------------------------------------------------------------------------------ -template -void g_fft::rifft1pt(FFT_TYPE *ioptr, FFT_TYPE scale) -{ - FFT_TYPE f0r, f0i; - FFT_TYPE t0r, t0i; - -// bit reversed load - f0r = ioptr[0]; - f0i = ioptr[1]; - -// finish rfft - t0r = f0r + f0i; - t0i = f0r - f0i; - -// store result - ioptr[0] = scale * t0r; - ioptr[1] = scale * t0i; -} - -//------------------------------------------------------------------------------ -// RADIX 4 rifft -//------------------------------------------------------------------------------ -template -void g_fft::rifft2pt(FFT_TYPE *ioptr, FFT_TYPE scale) -{ - FFT_TYPE f0r, f0i, f1r, f1i; - FFT_TYPE t0r, t0i; - const FFT_TYPE Two = FFT_TYPE(2.0); - -// bit reversed load - t0r = ioptr[0]; - t0i = ioptr[1]; - f1r = Two * ioptr[2]; - f1i = Two * ioptr[3]; - -// start rifft - f0r = t0r + t0i; - f0i = t0r - t0i; - -// Butterflys -// f0 - - t0 -// f1 - 1 - f1 - - t0r = f0r + f1r; - t0i = f0i - f1i; - f1r = f0r - f1r; - f1i = f0i + f1i; - -// store result - ioptr[0] = scale * t0r; - ioptr[1] = scale * t0i; - ioptr[2] = scale * f1r; - ioptr[3] = scale * f1i; -} - -//------------------------------------------------------------------------------ -// RADIX 8 rifft -//------------------------------------------------------------------------------ -template -void g_fft::rifft4pt(FFT_TYPE *ioptr, FFT_TYPE scale) -{ - FFT_TYPE f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; - FFT_TYPE t0r, t0i, t1r, t1i; - FFT_TYPE w0r = 1.0 / FFT_ROOT2; // cos(pi/4) - const FFT_TYPE Two = FFT_TYPE(2.0); - -// bit reversed load - t0r = ioptr[0]; - t0i = ioptr[1]; - f2r = ioptr[2]; - f2i = ioptr[3]; - f1r = Two * ioptr[4]; - f1i = Two * ioptr[5]; - f3r = ioptr[6]; - f3i = ioptr[7]; - -// start rfft - f0r = t0r + t0i; // compute Re(x[0]) - f0i = t0r - t0i; // compute Re(x[N/2]) - - t1r = f2r + f3r; - t1i = f2i - f3i; - t0r = f2r - f3r; - t0i = f2i + f3i; - - f2r = t1r - w0r * t0r - w0r * t0i; - f2i = t1i + w0r * t0r - w0r * t0i; - f3r = Two * t1r - f2r; - f3i = f2i - Two * t1i; - -// Butterflys -// f0 - - t0 - - f0 -// f1 - 1 - f1 - - f1 -// f2 - - f2 - 1 - f2 -// f3 - 1 - t1 - i - f3 - - t0r = f0r + f1r; - t0i = f0i - f1i; - f1r = f0r - f1r; - f1i = f0i + f1i; - - t1r = f2r - f3r; - t1i = f2i - f3i; - f2r = f2r + f3r; - f2i = f2i + f3i; - - f0r = t0r + f2r; - f0i = t0i + f2i; - f2r = t0r - f2r; - f2i = t0i - f2i; - - f3r = f1r + t1i; - f3i = f1i - t1r; - f1r = f1r - t1i; - f1i = f1i + t1r; - -// store result - ioptr[0] = scale * f0r; - ioptr[1] = scale * f0i; - ioptr[2] = scale * f1r; - ioptr[3] = scale * f1i; - ioptr[4] = scale * f2r; - ioptr[5] = scale * f2i; - ioptr[6] = scale * f3r; - ioptr[7] = scale * f3i; -} - -//------------------------------------------------------------------------------ -// RADIX 16 rifft -//------------------------------------------------------------------------------ -template -void g_fft::rifft8pt(FFT_TYPE *ioptr, FFT_TYPE scale) -{ - FFT_TYPE w0r = (FFT_TYPE) (1.0 / FFT_ROOT2); // cos(pi/4) - FFT_TYPE w1r = FFT_COSPID8; // cos(pi/8) - FFT_TYPE w1i = FFT_SINPID8; // sin(pi/8) - FFT_TYPE f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; - FFT_TYPE f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i; - FFT_TYPE t0r, t0i, t1r, t1i; - const FFT_TYPE Two = FFT_TYPE(2.0); - -// bit reversed load - t0r = ioptr[0]; - t0i = ioptr[1]; - f4r = ioptr[2]; - f4i = ioptr[3]; - f2r = ioptr[4]; - f2i = ioptr[5]; - f6r = ioptr[6]; - f6i = ioptr[7]; - f1r = Two * ioptr[8]; - f1i = Two * ioptr[9]; - f5r = ioptr[10]; - f5i = ioptr[11]; - f3r = ioptr[12]; - f3i = ioptr[13]; - f7r = ioptr[14]; - f7i = ioptr[15]; - -// start rfft - f0r = t0r + t0i; // compute Re(x[0]) - f0i = t0r - t0i; // compute Re(x[N/2]) - - t0r = f2r + f3r; - t0i = f2i - f3i; - t1r = f2r - f3r; - t1i = f2i + f3i; - - f2r = t0r - w0r * t1r - w0r * t1i; - f2i = t0i + w0r * t1r - w0r * t1i; - f3r = Two * t0r - f2r; - f3i = f2i - Two * t0i; - - t0r = f4r + f7r; - t0i = f4i - f7i; - t1r = f4r - f7r; - t1i = f4i + f7i; - - f4r = t0r - w1i * t1r - w1r * t1i; - f4i = t0i + w1r * t1r - w1i * t1i; - f7r = Two * t0r - f4r; - f7i = f4i - Two * t0i; - - t0r = f6r + f5r; - t0i = f6i - f5i; - t1r = f6r - f5r; - t1i = f6i + f5i; - - f6r = t0r - w1r * t1r - w1i * t1i; - f6i = t0i + w1i * t1r - w1r * t1i; - f5r = Two * t0r - f6r; - f5i = f6i - Two * t0i; - -// Butterflys -// f0 - - t0 - - f0 - - f0 -// f1* - 1 - f1 - - f1 - - f1 -// f2 - - f2 - 1 - f2 - - f2 -// f3 - 1 - t1 - i - f3 - - f3 -// f4 - - t0 - - f4 - 1 - t0 -// f5 - 1 - f5 - - f5 - w3 - f4 -// f6 - - f6 - 1 - f6 - i - t1 -// f7 - 1 - t1 - i - f7 - iw3- f6 - - t0r = f0r + f1r; - t0i = f0i - f1i; - f1r = f0r - f1r; - f1i = f0i + f1i; - - t1r = f2r - f3r; - t1i = f2i - f3i; - f2r = f2r + f3r; - f2i = f2i + f3i; - - f0r = t0r + f2r; - f0i = t0i + f2i; - f2r = t0r - f2r; - f2i = t0i - f2i; - - f3r = f1r + t1i; - f3i = f1i - t1r; - f1r = f1r - t1i; - f1i = f1i + t1r; - - t0r = f4r + f5r; - t0i = f4i + f5i; - f5r = f4r - f5r; - f5i = f4i - f5i; - - t1r = f6r - f7r; - t1i = f6i - f7i; - f6r = f6r + f7r; - f6i = f6i + f7i; - - f4r = t0r + f6r; - f4i = t0i + f6i; - f6r = t0r - f6r; - f6i = t0i - f6i; - - f7r = f5r + t1i; - f7i = f5i - t1r; - f5r = f5r - t1i; - f5i = f5i + t1r; - - t0r = f0r - f4r; - t0i = f0i - f4i; - f0r = f0r + f4r; - f0i = f0i + f4i; - - t1r = f2r + f6i; - t1i = f2i - f6r; - f2r = f2r - f6i; - f2i = f2i + f6r; - - f4r = f1r - f5r * w0r + f5i * w0r; - f4i = f1i - f5r * w0r - f5i * w0r; - f1r = f1r * Two - f4r; - f1i = f1i * Two - f4i; - - f6r = f3r + f7r * w0r + f7i * w0r; - f6i = f3i - f7r * w0r + f7i * w0r; - f3r = f3r * Two - f6r; - f3i = f3i * Two - f6i; - -// store result - ioptr[0] = scale * f0r; - ioptr[1] = scale * f0i; - ioptr[2] = scale * f1r; - ioptr[3] = scale * f1i; - ioptr[4] = scale * f2r; - ioptr[5] = scale * f2i; - ioptr[6] = scale * f3r; - ioptr[7] = scale * f3i; - ioptr[8] = scale * t0r; - ioptr[9] = scale * t0i; - ioptr[10] = scale * f4r; - ioptr[11] = scale * f4i; - ioptr[12] = scale * t1r; - ioptr[13] = scale * t1i; - ioptr[14] = scale * f6r; - ioptr[15] = scale * f6i; -} - -//------------------------------------------------------------------------------ -// Start RIFFT -//------------------------------------------------------------------------------ -template -void g_fft::ifrstage(FFT_TYPE *ioptr, int M, FFT_TYPE *Utbl) -{ - unsigned int pos; - unsigned int posi; - unsigned int diffUcnt; - - FFT_TYPE *p0r, *p1r; - FFT_TYPE *u0r, *u0i; - - FFT_TYPE w0r, w0i; - FFT_TYPE f0r, f0i, f1r, f1i, f4r, f4i, f5r, f5i; - FFT_TYPE t0r, t0i, t1r, t1i; - const FFT_TYPE Two = FFT_TYPE(2.0); - - pos = POW2(M - 1); - posi = pos + 1; - - p0r = ioptr; - p1r = ioptr + pos / 2; - - u0r = Utbl + POW2(M - 3); - - w0r = *u0r, f0r = *(p0r); - f0i = *(p0r + 1); - f4r = *(p0r + pos); - f4i = *(p0r + posi); - f1r = *(p1r); - f1i = *(p1r + 1); - f5r = *(p1r + pos); - f5i = *(p1r + posi); - - t0r = f0r + f0i; - t0i = f0r - f0i; - t1r = f4r + f4r; - t1i = -f4i - f4i; - - f0r = f1r + f5r; - f0i = f1i - f5i; - f4r = f1r - f5r; - f4i = f1i + f5i; - - f1r = f0r - w0r * f4r - w0r * f4i; - f1i = f0i + w0r * f4r - w0r * f4i; - f5r = Two * f0r - f1r; - f5i = f1i - Two * f0i; - - *(p0r) = t0r; - *(p0r + 1) = t0i; - *(p0r + pos) = t1r; - *(p0r + posi) = t1i; - *(p1r) = f1r; - *(p1r + 1) = f1i; - *(p1r + pos) = f5r; - *(p1r + posi) = f5i; - - u0r = Utbl + 1; - u0i = Utbl + (POW2(M - 2) - 1); - - w0r = *u0r, w0i = *u0i; - - p0r = (ioptr + 2); - p1r = (ioptr + (POW2(M - 2) - 1) * 2); - -// Butterflys -// f0 - t0 - f0 -// f1 - t1 -w0- f1 -// f2 - t0 - f2 -// f3 - t1 -iw0- f3 - - for (diffUcnt = POW2(M - 3) - 1; diffUcnt > 0; diffUcnt--) { - - f0r = *(p0r); - f0i = *(p0r + 1); - f5r = *(p1r + pos); - f5i = *(p1r + posi); - f1r = *(p1r); - f1i = *(p1r + 1); - f4r = *(p0r + pos); - f4i = *(p0r + posi); - - t0r = f0r + f5r; - t0i = f0i - f5i; - t1r = f0r - f5r; - t1i = f0i + f5i; - - f0r = t0r - w0i * t1r - w0r * t1i; - f0i = t0i + w0r * t1r - w0i * t1i; - f5r = Two * t0r - f0r; - f5i = f0i - Two * t0i; - - t0r = f1r + f4r; - t0i = f1i - f4i; - t1r = f1r - f4r; - t1i = f1i + f4i; - - f1r = t0r - w0r * t1r - w0i * t1i; - f1i = t0i + w0i * t1r - w0r * t1i; - f4r = Two * t0r - f1r; - f4i = f1i - Two * t0i; - - *(p0r) = f0r; - *(p0r + 1) = f0i; - *(p1r + pos) = f5r; - *(p1r + posi) = f5i; - - w0r = *++u0r; - w0i = *--u0i; - - *(p1r) = f1r; - *(p1r + 1) = f1i; - *(p0r + pos) = f4r; - *(p0r + posi) = f4i; - - p0r += 2; - p1r -= 2; - } -} - -//------------------------------------------------------------------------------ -// Compute in-place real ifft on the rows of the input array -// data order as from rffts1 -// INPUTS -// *ioptr = input data array in the following order -// M = log2 of fft size -// Re(x[0]), Re(x[N/2]), Re(x[1]), Im(x[1]), -// Re(x[2]), Im(x[2]), ... Re(x[N/2-1]), Im(x[N/2-1]). -// *Utbl = cosine table -// *BRLow = bit reversed counter table -// OUTPUTS -// *ioptr = real output data array -//------------------------------------------------------------------------------ -template -void g_fft::riffts1(FFT_TYPE *ioptr, int M, FFT_TYPE *Utbl, short *BRLow) -{ - FFT_TYPE scale; - int StageCnt; - int NDiffU; - - scale = (FFT_TYPE)(1.0 / (double)((int)POW2(M))); - M = M - 1; - switch (M) { - case -1: - break; - case 0: - rifft1pt(ioptr, scale); // a 2 pt fft - break; - case 1: - rifft2pt(ioptr, scale); // a 4 pt fft - break; - case 2: - rifft4pt(ioptr, scale); // an 8 pt fft - break; - case 3: - rifft8pt(ioptr, scale); // a 16 pt fft - break; - default: - ifrstage(ioptr, M + 1, Utbl); -// bit reverse and first radix 2 stage - scbitrevR2(ioptr, M, BRLow, scale); - StageCnt = (M - 1) / 3; // number of radix 8 stages - NDiffU = 2; // one radix 2 stage already complete - if ((M - 1 - (StageCnt * 3)) == 1) { - ibfR2(ioptr, M, NDiffU); // 1 radix 2 stage - NDiffU *= 2; - } - if ((M - 1 - (StageCnt * 3)) == 2) { - ibfR4(ioptr, M, NDiffU); // 1 radix 4 stage - NDiffU *= 4; - } - if (M <= (int) MCACHE) - ibfstages(ioptr, M, Utbl, 2, NDiffU, StageCnt); // RADIX 8 Stages - else - ifftrecurs(ioptr, M, Utbl, 2, NDiffU, StageCnt); // RADIX 8 Stages - } -} - -//============================================================================== -// End of original C functions -// -// Wrapper methods for simple class access -//============================================================================== - -//------------------------------------------------------------------------------ -// malloc and init cosine and bit reversed tables for a given size -// fft, ifft, rfft, rifft -// INPUTS -// M = log2 of fft size (ex M=10 for 1024 point fft) -// OUTPUTS -// private cosine and bit reversed tables -//------------------------------------------------------------------------------ -template -void g_fft::fftInit() -{ - for (int i = 0; i < 32; i++) { - FFT_table_1[i] = (FFT_TYPE*)0; - FFT_table_2[i] = (short int*)0; - } - - FFT_N = ConvertFFTSize(FFT_size); - -// create and initialize cos table - FFT_table_1[FFT_N] = new FFT_TYPE[(POW2(FFT_N) / 4 + 1)]; - fftCosInit(FFT_N, FFT_table_1[FFT_N]); - -// create and initialize bit reverse tables - FFT_table_2[FFT_N/2] = new short[POW2(FFT_N/2 - 1)]; - fftBRInit(FFT_N, FFT_table_2[FFT_N/2]); - - FFT_table_2[(FFT_N - 1) / 2] = new short[POW2((FFT_N - 1) / 2 - 1)]; - fftBRInit(FFT_N - 1, FFT_table_2[(FFT_N - 1) / 2]); - - Utbl = ((FFT_TYPE**) FFT_table_1)[FFT_N]; - BRLow = ((short**) FFT_table_2)[FFT_N / 2]; - -} - -//------------------------------------------------------------------------------ -// convert from N to LOG2(N) -//------------------------------------------------------------------------------ -template -int g_fft::ConvertFFTSize(int N) -{ - if (N <= 0) N = -N; - - switch (N) { - case 0x00000001: return 0; // 1 - case 0x00000002: return 1; // 2 - case 0x00000004: return 2; // 4 - case 0x00000008: return 3; // 8 - case 0x00000010: return 4; // 16 - case 0x00000020: return 5; // 32 - case 0x00000040: return 6; // 64 - case 0x00000080: return 7; // 128 - case 0x00000100: return 8; // 256 - case 0x00000200: return 9; // 512 - case 0x00000400: return 10; // 1024 - case 0x00000800: return 11; // 2048 - case 0x00001000: return 12; // 4096 - case 0x00002000: return 13; // 8192 - case 0x00004000: return 14; // 16384 - case 0x00008000: return 15; // 32768 - case 0x00010000: return 16; // 65536 - case 0x00020000: return 17; // 131072 - case 0x00040000: return 18; // 262144 - case 0x00080000: return 19; // 525288 - case 0x00100000: return 20; // 1048576 - case 0x00200000: return 21; // 2097152 - case 0x00400000: return 22; // 4194304 - case 0x00800000: return 23; // 8388608 - case 0x01000000: return 24; // 16777216 - case 0x02000000: return 25; // 33554432 - case 0x04000000: return 26; // 67108864 - case 0x08000000: return 27; // 134217728 - case 0x10000000: return 28; // 268435456 - } - return 0; -} - -//------------------------------------------------------------------------------ -// Compute in-place complex FFT -// FFTsize: FFT length in samples -// buf: array of FFTsize*2 FFT_TYPE values, -// in interleaved real/imaginary format -//------------------------------------------------------------------------------ -template -void g_fft::ComplexFFT(std::complex *buf) -{ - void *ptr = buf; - FFT_TYPE *nbuf = static_cast(ptr); - ffts1(nbuf, FFT_N, Utbl, BRLow); -} - -//------------------------------------------------------------------------------ -// Compute in-place inverse complex FFT -// FFTsize: FFT length in samples -// buf: array of FFTsize*2 FFT_TYPE values, -// in interleaved real/imaginary format -// Output should be scaled by the return value of -// GetInverseComplexFFTScale(fft_struct, FFTsize). -//------------------------------------------------------------------------------ -template -void g_fft::InverseComplexFFT(std::complex *buf) -{ - void *ptr = buf; - FFT_TYPE *nbuf = static_cast(ptr); - iffts1(nbuf, FFT_N, Utbl, BRLow); -} - -//------------------------------------------------------------------------------ -// Compute in-place real FFT -// FFTsize: FFT length in samples -// buf: array of FFTsize FFT_TYPE values; output is in interleaved -// real/imaginary format, except for buf[1] which is the real -// part for the Nyquist frequency -//------------------------------------------------------------------------------ -template -void g_fft::RealFFT(std::complex *buf) -{ - void *ptr = buf; - FFT_TYPE *nbuf = static_cast(ptr); - rffts1(nbuf, FFT_N, Utbl, BRLow); -} - -//------------------------------------------------------------------------------ -// Compute in-place inverse real FFT -// FFTsize: FFT length in samples -// buf: array of FFTsize FFT_TYPE values; input is expected to be in -// interleaved real/imaginary format, except for buf[1] which -// is the real part for the Nyquist frequency -// Output should be scaled by the return value of -// GetInverseRealFFTScale(fft_struct, FFTsize). -//------------------------------------------------------------------------------ -template -void g_fft::InverseRealFFT(std::complex *buf) -{ - void *ptr = buf; - FFT_TYPE *nbuf = static_cast(ptr); - riffts1(nbuf, FFT_N, Utbl, BRLow); -} - -//------------------------------------------------------------------------------ -// Returns the amplitude scale that should be applied to the result of -// an inverse complex FFT with a length of 'FFTsize' samples. -//------------------------------------------------------------------------------ -template -FFT_TYPE g_fft::GetInverseComplexFFTScale() -{ - return FFT_TYPE(1.0); -} - -//------------------------------------------------------------------------------ -// Returns the amplitude scale that should be applied to the result of -// an inverse real FFT with a length of 'FFTsize' samples. -//------------------------------------------------------------------------------ -template -FFT_TYPE g_fft::GetInverseRealFFTScale() -{ - return FFT_TYPE(1.0); -} - -#endif - diff --git a/feature/cw/src/main/cpp/fldigi/mbuffer.h b/feature/cw/src/main/cpp/fldigi/mbuffer.h deleted file mode 100644 index 1a5ce46b..00000000 --- a/feature/cw/src/main/cpp/fldigi/mbuffer.h +++ /dev/null @@ -1,258 +0,0 @@ -// ---------------------------------------------------------------------------- -// mbuffer.h -// -// Copyright (C) 2007 -// Stelios Bounanos, M0GLD -// -// This file is part of fldigi. -// -// fldigi 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. -// -// fldigi 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 . -// ---------------------------------------------------------------------------- - - -// A simple vector wrapper for fldigi's double-buffering needs. -// Most vector operations are provided for mbuffers by redirecting them to the -// current vector. - -// The template arguments are -// 1) T - the type -// 2) S - the apparent mbuffer size, i.e., the size of each vector. Defaults to 0. -// A mbuffer instantiated with S == 0 is not very useful until resized -// with alloc(). -// 3) N - the number of vectors that we can cycle between. Defaults to 1. - -// Things to note: -// 1) There is a T* conversion operator -// 2) Operations that modify the length of the container are not provided -// 3) Comparison operators are not implemented (but see (1)!) -// 4) mbuffer is meant to be used when we don't know the size at -// compile time, in which case we resize with alloc. The compiler will treat -// mbuffers resized to different lengths in this way as objects of the same type. - -#ifndef MBUFFER_H -#define MBUFFER_H - -#include -#include - -#ifndef NDEBUG -#include -#include -#endif - -#ifndef NDEBUG -template -class mbuffer; -template -std::ostream& operator<<(std::ostream& o, const mbuffer& b); -#endif // NDEBUG - -template -class mbuffer -{ -protected: - std::vector data[N]; - mutable std::size_t cur; - -public: - explicit mbuffer(void) - { - alloc(S); - } - explicit mbuffer(std::size_t n) - { - alloc(n); - } - mbuffer(const std::vector& v) - { - data[0] = v; - // resize 1 to N only - alloc(data[0].size(), 1); - } - mbuffer(const T* a, std::size_t n) - { - data[0].assign(a, a + n); - // resize 1 to N only - alloc(n, 1); - } - void alloc(std::size_t n, std::size_t start = 0) - { - for (size_t i = start; i < N; ++i) - data[i].resize(n); - cur = 0; - } - - typedef typename std::vector::iterator iterator; - typedef typename std::vector::const_iterator const_iterator; - - iterator begin(void) { return data[cur].begin(); } - const_iterator begin(void) const { return data[cur].begin(); } - iterator end(void) { return data[cur].end(); } - const_iterator end(void) const { return data[cur].end(); } - - - typedef typename std::vector::reverse_iterator reverse_iterator; - typedef typename std::vector::const_reverse_iterator const_reverse_iterator; - - reverse_iterator rbegin(void) { return reverse_iterator(end()); } - const_reverse_iterator rbegin(void) const { return const_reverse_iterator(end()); } - reverse_iterator rend(void) { return reverse_iterator(begin()); } - const_reverse_iterator rend(void) const { return const_reverse_iterator(begin()); } - - - typedef typename std::vector::value_type value_type; - typedef typename std::vector::reference reference; - typedef typename std::vector::const_reference const_reference; - typedef typename std::vector::size_type size_type; - typedef typename std::vector::difference_type difference_type; - - // These should be the same for all vectors in data[] - size_type size(void) { return data[0].size(); } - size_type max_size(void) { return data[0].max_size(); } - size_type capacity(void) { return data[0].capacity(); } - bool empty(void) { return data[0].empty(); } - - // Instead of these, we provide a conversion operator for T* - // reference operator[](size_type i) { return data[cur][i]; } - // const_reference operator[](size_type i) const { return data[cur][i]; } - reference at(size_type i) { return data[cur].at(i); } - const_reference at(size_type i) const { return data[cur].at(i); } - reference front(void) { return data[cur].front(); } - const_reference front(void) const { return data[cur].front(); } - reference back(void) { return data[cur].back(); } - const_reference back(void) const { return data[cur].back(); } - - - // Operations that modify the size of data[cur] might invalidate - // pointers to internal buffers. The rest of the data vectors would need - // to be resized, e.g. with check_size below. For this reason these - // operations are not provided, but are included here for completeness - - // void check_size(void) - // { - // for (size_t i = 0; i < N; ++i) - // if (data[i].size() != data[cur].size()) - // data[i].resize(data[cur].size()); - // } - - // mbuffer& operator=(const mbuffer& o) - // { - // for (int i = 0; i < N; ++i) - // std::copy(o.data[i].begin(), o.data[i].end(), data[i].begin()); - // return *this; - // } - // std::vector& operator=(const std::vector& o) - // { - // std::copy(o.begin(), o.end(), data[cur].begin()); - // check_size(); - // return data[cur]; - // } - - // The methods below would modify the length of the vector. - // We would need to check_size() before returning from them. - - // There is no vector::assign; the one provided here fills the vector - // with copies of the same value without causing a resize. - void assign(const_reference v) { std::fill_n(begin(), size(), v); } - // template - // void assign(input_iterator first, input_iterator last) - // { - // data[cur].assign(first, last); - // } - - // void push_back(const_reference v) { data[cur].push_back(v); } - // void pop_back(void) { data[cur].pop_back(); } - - // iterator insert(iterator pos, const_reference v) - // { - // return data[cur].insert(pos, v); - // } - // iterator insert(iterator pos, size_type n, const_reference v) - // { - // return data[cur].insert(pos, n, v); - // } - // template - // void insert(iterator pos, input_iterator first, input_iterator last) - // { - // data[cur].insert(pos, first, last); - // } - - // iterator erase(iterator pos) { return data[cur].erase(pos); } - // iterator erase(iterator first, iterator last) { return data[cur].erase(first, last); } - - // void clear(void) { data[cur].clear(); } - - void swap(mbuffer& o) - { - for (int i = 0; i < N; ++i) - std::swap(data[i].begin(), data[i].end(), o.data[i].begin()); - } - // void swap(std::vector& o) - // { - // std::swap(data[cur].begin(), data[cur].end(), o.begin()); - // check_size(); - // o.check_size(); - // } - - - // and now for something completely different - - void next(void) const { if (++cur == N) cur = 0; } - void prev(void) const { if (cur > 0) --cur; } - void reset(void) const { cur = 0; } - - T* c_array(void) { return &data[cur][0]; } - operator T*(void) { return c_array(); } - const T* c_array(void) const { return &data[cur][0]; } - operator const T*(void) const { return c_array(); } - - std::vector& vec(void) { return data[cur]; } - const std::vector& vec(void) const { return data[cur]; } - // We also do not provide vector conversions - // operator std::vector&(void) { return vec(); } - // operator const std::vector&(void) const { return vec(); } - - std::size_t idx(void) { return cur; } - std::size_t nvec(void) { return N; } - std::vector* vecp(std::size_t i) { return &data[i]; } - -#ifndef NDEBUG - friend std::ostream& operator<<<>(std::ostream& o, const mbuffer& b); -#endif // NDEBUG -}; - -#ifndef NDEBUG -template -std::ostream& operator<<(std::ostream& o, const mbuffer& b) -{ - for (std::size_t i = 0; i < N; ++i) { - o << '<' << i << ">\n"; - copy(b.data[i].begin(), b.data[i].end(), - std::ostream_iterator(o, "\n")); - } - - return o; -} -#endif // NDEBUG - -template -inline -void swap(mbuffer& a, mbuffer& b) { a.swap(b); } - -#endif // MBUFFER_H - -// Local Variables: -// mode: c++ -// c-file-style: "linux" -// End: diff --git a/feature/cw/src/main/cpp/fldigi/modem.h b/feature/cw/src/main/cpp/fldigi/modem.h deleted file mode 100644 index 0bae32f0..00000000 --- a/feature/cw/src/main/cpp/fldigi/modem.h +++ /dev/null @@ -1,160 +0,0 @@ -// ---------------------------------------------------------------------------- -// modem.h -- minimal modem base class for fldigi CW decoder (Android) -// Extracted from fldigi/src/include/modem.h (GPL v3). -// ---------------------------------------------------------------------------- -#ifndef _MODEM_H -#define _MODEM_H - -#include -#include -#include "morse.h" -#include "filters.h" - -#define OUTBUFSIZE 65536 - -enum trx_mode { - MODE_CW = 0 -}; - -struct mode_info_t { - const char *sname; - unsigned int iface_io; -}; - -namespace Digiscope { - enum scope_mode { SCOPE, SCOPE2, PHASE, PHASE2, WATERFALL, NONE }; -} - -class modem { -public: - static double frequency; - static double tx_frequency; - static bool freqlock; - static unsigned long tx_sample_count; - static unsigned int tx_sample_rate; - static bool XMLRPC_CPS_TEST; - -protected: - cMorse *morse; - trx_mode mode; - bool stopflag; - int fragmentsize; - int samplerate; - bool reverse; - int sigsearch; - bool sig_start; - bool sig_stop; - double bandwidth; - double freqerr; - double rx_corr; - double tx_corr; - double PTTphaseacc; - double PTTchannel[OUTBUFSIZE]; - bool cwTrack; - bool cwLock; - double cwRcvWPM; - double cwXmtWPM; - double squelch; - double metric; - double syncpos; - int backspaces; - unsigned char *txstr; - unsigned char *txptr; - double outbuf[OUTBUFSIZE]; - bool historyON; - Digiscope::scope_mode scopemode; - int scptr; - double s2n_ncount, s2n_sum, s2n_sum2, s2n_metric; - bool s2n_valid; - unsigned cap; - std::string audio_filename; - bool play_audio; - bool CW_EOT; - -public: - modem(); - virtual ~modem() { delete morse; } - virtual void init(); - virtual void tx_init() = 0; - virtual void rx_init() = 0; - virtual void restart() = 0; - virtual void rx_flush() {} - virtual int tx_process(); - virtual int rx_process(const double *, int len) = 0; - virtual void Audio_filename(std::string nm) { audio_filename = nm; play_audio = true; } - virtual void shutdown() {} - virtual void set1(int, int) {} - virtual void set2(int, int) {} - virtual void makeTxViewer(int W, int H) {} - virtual void searchDown() {} - virtual void searchUp() {} - void HistoryON(bool val) { historyON = val; } - bool HistoryON() const { return historyON; } - trx_mode get_mode() const { return mode; } - const char *get_mode_name() const; - unsigned int iface_io() const; - virtual void set_freq(double); - int get_freq() const { return (int)(frequency + 0.5); } - void init_freqlock(); - void set_freqlock(bool); - void set_sigsearch(int n) { sigsearch = n; freqerr = 0.0; } - bool freqlocked() const { return freqlock; } - double get_txfreq() const; - double get_txfreq_woffset() const; - void set_metric(double); - void display_metric(double); - double get_metric() const { return metric; } - void set_reverse(bool on); - bool get_reverse() const { return reverse; } - double get_bandwidth() const { return bandwidth; } - void set_bandwidth(double); - int get_samplerate() const { return samplerate; } - void set_samplerate(int); - void init_queues(); - void ModulateXmtr(double *, int); - void ModulateStereo(double *, double *, int, bool sample_flag = true); - void ModulateVideo(double *, int); - void ModulateVideoStereo(double *, double *, int, bool sample_flag = true); - void videoText(); - void pretone(); - virtual void send_color_image(std::string) {} - virtual void send_Grey_image(std::string) {} - virtual void ifkp_send_image(std::string s = "", bool grey = false) {} - virtual void ifkp_send_avatar() {} - virtual void m_ifkp_send_avatar() {} - virtual void thor_send_image(std::string s = "", bool grey = false) {} - virtual void thor_send_avatar() {} - virtual void m_thor_send_avatar() {} - void set_stopflag(bool b) { stopflag = b; } - bool get_stopflag() const { return stopflag; } - unsigned get_cap() const { return cap; } - enum { CAP_AFC = 1 << 0, CAP_AFC_SR = 1 << 1, CAP_REV = 1 << 2, - CAP_IMG = 1 << 3, CAP_BW = 1 << 4, CAP_RX = 1 << 5, - CAP_TX = 1 << 6 }; - - bool get_cwTrack(); - void set_cwTrack(bool); - bool get_cwLock(); - void set_cwLock(bool); - double get_cwXmtWPM(); - void set_cwXmtWPM(double); - double get_cwRcvWPM(); - virtual void CW_KEYLINE(bool) {} - virtual void incWPM() {} - virtual void decWPM() {} - virtual void toggleWPM() {} - virtual void sync_parameters() {} - virtual void reset_rx_filter() {} - virtual void update_Status() {} - virtual void refresh_scope() {} - virtual void clear_viewer() {} - virtual void clear_ch(int n) {} - virtual int viewer_get_freq(int n) { return 0; } - double calWPM() { return 20; } - void calWPM(double) {} - void resetFSK() {} - void s2nreport() {} - void set_scope_mode(Digiscope::scope_mode sm) { scopemode = sm; } -}; - -#endif \ No newline at end of file diff --git a/feature/cw/src/main/cpp/fldigi/morse.cxx b/feature/cw/src/main/cpp/fldigi/morse.cxx deleted file mode 100644 index 68545b00..00000000 --- a/feature/cw/src/main/cpp/fldigi/morse.cxx +++ /dev/null @@ -1,314 +0,0 @@ -/* - * morse.c -- morse code tables - * - * Copyright (C) 2017 - * - * Fldigi 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. - * - * Fldigi 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 fldigi. If not, see . - * - */ - -#include -#include -#include - -#include "morse.h" -#include "configuration.h" - -/* ---------------------------------------------------------------------- */ - -/* - * Morse code characters table. This table allows lookup of the Morse - * shape of a given alphanumeric character. Shapes are held as a string, - * with "-' representing dash, and ".' representing dot. The table ends - * with a NULL entry. - * - * This is the main table from which the other tables are computed. - * - * The Prosigns are also defined in the configuration.h file - * The user can specify the character which substitutes for the prosign - */ - -bool CW_table_changed = false; - -CWstruct cMorse::cw_table[] = { -// Prosigns - {1, "=", "", "-...-" }, // 0 - {0, "~", "", ".-.-" }, // 1 - {1, "<", "", ".-..." }, // 2 - {1, ">", "", ".-.-." }, // 3 - {1, "%", "", "...-.-" }, // 4 - {1, "+", "", "-.--." }, // 5 - {1, "&", "", "..-.-" }, // 6 - {1, "{", "", "....--" }, // 7 - {1, "}", "", "...-." }, // 8 -// ASCII 7bit letters - {1, "A", "A", ".-" }, - {1, "B", "B", "-..." }, - {1, "C", "C", "-.-." }, - {1, "D", "D", "-.." }, - {1, "E", "E", "." }, - {1, "F", "F", "..-." }, - {1, "G", "G", "--." }, - {1, "H", "H", "...." }, - {1, "I", "I", ".." }, - {1, "J", "J", ".---" }, - {1, "K", "K", "-.-" }, - {1, "L", "L", ".-.." }, - {1, "M", "M", "--" }, - {1, "N", "N", "-." }, - {1, "O", "O", "---" }, - {1, "P", "P", ".--." }, - {1, "Q", "Q", "--.-" }, - {1, "R", "R", ".-." }, - {1, "S", "S", "..." }, - {1, "T", "T", "-" }, - {1, "U", "U", "..-" }, - {1, "V", "V", "...-" }, - {1, "W", "W", ".--" }, - {1, "X", "X", "-..-" }, - {1, "Y", "Y", "-.--" }, - {1, "Z", "Z", "--.." }, -// - {1, "a", "A", ".-" }, - {1, "b", "B", "-..." }, - {1, "c", "C", "-.-." }, - {1, "d", "D", "-.." }, - {1, "e", "E", "." }, - {1, "f", "F", "..-." }, - {1, "g", "G", "--." }, - {1, "h", "H", "...." }, - {1, "i", "I", ".." }, - {1, "j", "J", ".---" }, - {1, "k", "K", "-.-" }, - {1, "l", "L", ".-.." }, - {1, "m", "M", "--" }, - {1, "n", "N", "-." }, - {1, "o", "O", "---" }, - {1, "p", "P", ".--." }, - {1, "q", "Q", "--.-" }, - {1, "r", "R", ".-." }, - {1, "s", "S", "..." }, - {1, "t", "T", "-" }, - {1, "u", "U", "..-" }, - {1, "v", "V", "...-" }, - {1, "w", "W", ".--" }, - {1, "x", "X", "-..-" }, - {1, "y", "Y", "-.--" }, - {1, "z", "Z", "--.." }, -// Numerals - {1, "0", "0", "-----" }, - {1, "1", "1", ".----" }, - {1, "2", "2", "..---" }, - {1, "3", "3", "...--" }, - {1, "4", "4", "....-" }, - {1, "5", "5", "....." }, - {1, "6", "6", "-...." }, - {1, "7", "7", "--..." }, - {1, "8", "8", "---.." }, - {1, "9", "9", "----." }, -// Punctuation - {1, "\\", "\\", ".-..-." }, - {1, "\'", "'", ".----." }, - {1, "$", "$", "...-..-" }, - {1, "(", "(", "-.--." }, - {1, ")", ")", "-.--.-" }, - {1, ",", ",", "--..--" }, - {1, "-", "-", "-....-" }, - {1, ".", ".", ".-.-.-" }, - {1, "/", "/", "-..-." }, - {1, ":", ":", "---..." }, - {1, ";", ";", "-.-.-." }, - {1, "?", "?", "..--.." }, - {1, "_", "_", "..--.-" }, - {1, "@", "@", ".--.-." }, - {1, "!", "!", "-.-.--" }, -// accented characters - {1, "Ä", "Ä", ".-.-" }, // A umlaut - {1, "ä", "Ä", ".-.-" }, // A umlaut - {0, "Æ", "Æ", ".-.-" }, // A aelig - {0, "æ", "Æ", ".-.-" }, // A aelig - {0, "Å", "Å", ".--.-" }, // A ring - {0, "å", "Å", ".--.-" }, // A ring - {1, "Ç", "Ç", "-.-.." }, // C cedilla - {1, "ç", "Ç", "-.-.." }, // C cedilla - {0, "È", "È", ".-..-" }, // E grave - {0, "è", "È", ".-..-" }, // E grave - {1, "É", "É", "..-.." }, // E acute - {1, "é", "É", "..-.." }, // E acute - {0, "Ó", "Ó", "---." }, // O acute - {0, "ó", "Ó", "---." }, // O acute - {1, "Ö", "Ö", "---." }, // O umlaut - {1, "ö", "Ö", "---." }, // O umlaut - {0, "Ø", "Ø", "---." }, // O slash - {0, "ø", "Ø", "---." }, // O slash - {1, "Ñ", "Ñ", "--.--" }, // N tilde - {1, "ñ", "Ñ", "--.--" }, // N tilde - {1, "Ü", "Ü", "..--" }, // U umlaut - {1, "ü", "Ü", "..--" }, // U umlaut - {0, "Û", "Û", "..--" }, // U circ - {0, "û", "Û", "..--" }, // U circ -// array termination - {0, "", "", ""} -}; - -/* ---------------------------------------------------------------------- */ - -void cMorse::enable(std::string s, bool val) -{ - for (int i = 0; cw_table[i].rpr.length(); i++) { - if (cw_table[i].chr == s || cw_table[i].prt == s) { - cw_table[i].enabled = val; - return; - } - } -} - -void cMorse::init() -{ -// Update the char / prosign relationship - if (progdefaults.CW_prosigns.length() == 9) { - for (int i = 0; i < 9; i++) { - cw_table[i].chr = progdefaults.CW_prosigns[i]; - } - } - enable("", 1); - enable("Ä", 0); enable("ä", 0); - enable("Æ", 0); enable("æ", 0); - enable("Å", 0); enable("å", 0); - enable("Ç", 0); enable("ç", 0); - enable("È", 0); enable("è", 0); - enable("É", 0); enable("é", 0); - enable("Ó", 0); enable("ó", 0); - enable("Ö", 0); enable("ö", 0); - enable("Ø", 0); enable("ø", 0); - enable("Ñ", 0); enable("ñ", 0); - enable("Ü", 0); enable("ü", 0); - enable("Û", 0); enable("û", 0); - - if (progdefaults.A_umlaut) - { enable("Ä", 1); enable("ä", 1); enable("", 0); } - if (progdefaults.A_aelig) - { enable("Æ", 1); enable("æ", 1); enable("", 0); } - if (progdefaults.A_ring) - { enable("Å", 1); enable("å", 1); } - if (progdefaults.C_cedilla) - { enable("Ç", 1); enable("ç", 1); } - if (progdefaults.E_grave) - { enable("È", 1); enable("è", 1); } - if (progdefaults.E_acute) - { enable("É", 1); enable("é", 1); } - if (progdefaults.O_acute) - { enable("Ó", 1); enable("ó", 1); } - if (progdefaults.O_umlaut) - { enable("Ö", 1); enable("ö", 1); } - if (progdefaults.O_slash) - { enable("Ø", 1); enable("ø", 1); } - if (progdefaults.N_tilde) - { enable("Ñ", 1); enable("ñ", 1); } - if (progdefaults.U_umlaut) - { enable("Ü", 1); enable("ü", 1); } - if (progdefaults.U_circ) - { enable("Û", 1); enable("û", 1); } - - enable ("\\", progdefaults.CW_backslash); - enable ("\'", progdefaults.CW_single_quote); - enable ("$", progdefaults.CW_dollar_sign); - enable ("(", progdefaults.CW_open_paren); - enable (")", progdefaults.CW_close_paren); - enable (":", progdefaults.CW_colon); - enable (";", progdefaults.CW_semi_colon); - enable ("_", progdefaults.CW_underscore); - enable ("@", progdefaults.CW_at_symbol); - enable ("!", progdefaults.CW_exclamation); - - CW_table_changed = false; - utf8.reserve(4); - utf8.clear(); - ptr = 0; - toprint.clear(); -} - -std::string cMorse::rx_lookup(std::string rx) -{ - if (CW_table_changed) init(); - for (int i = 0; cw_table[i].rpr.length(); i++) { - if (rx == cw_table[i].rpr) { - if (cw_table[i].enabled) { - if (progdefaults.CW_prosign_display) - return cw_table[i].chr; - return cw_table[i].prt; - } - } - } - return ""; -} - -std::string cMorse::tx_lookup(int c) -{ - if (CW_table_changed) init(); - toprint.clear(); - - c &= 0xFF; - utf8 += c; -// if (ptr < 4) utf8[ptr++] = c; - -// if ( c > 0x7F && ptr == 1 ) -// return ""; - if (((utf8[0] & 0xFF) > 0x7F) && (utf8.length() == 1)) { - return ""; - } - - for (int i = 0; cw_table[i].rpr.length(); i++) { - if (utf8 == cw_table[i].chr) { - if (!cw_table[i].enabled) { - utf8.clear(); - ptr = 0; - return ""; - } - toprint = cw_table[i].prt; - utf8.clear(); - ptr = 0; - return cw_table[i].rpr; - } - } - utf8.clear(); - ptr = 0; - return ""; - -} - -/* -Morse Code timing rules - The length of a dot is 1 time unit. - A dash is 3 time units. - The space between symbols (dots and dashes) of the same letter is 1 time unit. - The space between letters is 3 time units. - The space between words is 7 time units. -*/ -int cMorse::tx_length(int c) -{ - if (c == ' ') return 4; - std::string ms = tx_lookup(c); - if (ms.empty()) return 0; - int len = 0; - for (size_t i = 0; i < ms.length(); i++) - if (ms[i] == '.') len += 2; - else len += 4; - len += 2; - return len; -} - - -/* ---------------------------------------------------------------------- */ - diff --git a/feature/cw/src/main/cpp/fldigi/morse.h b/feature/cw/src/main/cpp/fldigi/morse.h deleted file mode 100644 index 7d03fe43..00000000 --- a/feature/cw/src/main/cpp/fldigi/morse.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * morse.h -- morse code tables - * - * Copyright (C) 2017 - * - * Fldigi 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. - * - * Fldigi 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 fldigi. If not, see . - * - */ - -#ifndef _MORSE_H -#define _MORSE_H - -#include - -#define MorseTableSize 256 - -#define CW_DOT_REPRESENTATION '.' -#define CW_DASH_REPRESENTATION '-' - -struct CWstruct { - bool enabled; // true if character is active - std::string chr; // utf-8 string representation of character - std::string prt; // utf-8 printable representation - std::string rpr; // Dot-dash code representation -}; - -class cMorse { -private: - static CWstruct cw_table[]; - std::string utf8; - std::string toprint; - int ptr; -public: - cMorse() { - init(); - } - ~cMorse() { - } - void init(); - void enable(std::string, bool); - std::string rx_lookup(std::string); - std::string tx_lookup(int); - std::string tx_print() { return toprint; } - int tx_length(int); -}; - -#endif diff --git a/feature/cw/src/main/cpp/fldigi/view_cw.h b/feature/cw/src/main/cpp/fldigi/view_cw.h deleted file mode 100644 index 820c5b92..00000000 --- a/feature/cw/src/main/cpp/fldigi/view_cw.h +++ /dev/null @@ -1,24 +0,0 @@ -// ---------------------------------------------------------------------------- -// view_cw.h -- placeholder for fldigi CW waterfall view (Android) -// Replaces fldigi/src/include/view_cw.h (FLTK-based). Stub for compilation. -// ---------------------------------------------------------------------------- -#ifndef _VIEW_CW_H -#define _VIEW_CW_H - -#include - -class view_cw { -public: - view_cw() {} - ~view_cw() {} - - void restart() {} - - void setFreq(double freq) {} - void setSampleRate(int sr) {} - - // Data buffer for waterfall (populated by cw decoder, read by Android UI) - std::vector spectrum; -}; - -#endif \ No newline at end of file diff --git a/feature/cw/src/main/cpp/fldigi_cw_jni.cpp b/feature/cw/src/main/cpp/fldigi_cw_jni.cpp deleted file mode 100644 index 6ed29bd9..00000000 --- a/feature/cw/src/main/cpp/fldigi_cw_jni.cpp +++ /dev/null @@ -1,88 +0,0 @@ -// ---------------------------------------------------------------------------- -// fldigi_cw_jni.cpp -- JNI wrapper for fldigi CW decoder (Android) -// Copyright (C) 2026 atsunatsu -// GPL v3 -// ---------------------------------------------------------------------------- - -#include -#include -#include "fldigi/cw.h" -#include "fldigi/android_compat.h" - -// ============================================================================ -// Global definitions (declared extern in android_compat.h / used by cw.cxx) -// ============================================================================ - -waterfall_stub* wf = new waterfall_stub(); - -AndroidProgDefaults progdefaults; -AndroidProgStatus progStatus; - -bool use_nanoIO = false; -void set_nanoWPM(int wpm) {} -void set_nanoCW() {} - -// UI/status stubs -void put_cwRcvWPM(int) {} -void put_MODEstatus(const char*, ...) {} -void set_scope_xaxis_1(double) {} -void set_scope_xaxis(double) {} -void update_Status() {} - -// misc helpers -void set_scope_mode(int) {} -void put_rx_char(int c) {} -void put_echo_char(int c) {} - -double zmsec() { return 0.0; } -void MilliSleep(int) {} - -// ============================================================================ -// JNI Exports -// ============================================================================ - -extern "C" JNIEXPORT jlong JNICALL -Java_com_rtbishop_look4sat_feature_cw_FldigiNative_create(JNIEnv* env, jobject thiz) { - cw* decoder = new cw(); - decoder->init(); - return reinterpret_cast(decoder); -} - -extern "C" JNIEXPORT void JNICALL -Java_com_rtbishop_look4sat_feature_cw_FldigiNative_destroy(JNIEnv* env, jobject thiz, jlong handle) { - cw* decoder = reinterpret_cast(handle); - if (decoder) { - decoder->rx_init(); - delete decoder; - } -} - -extern "C" JNIEXPORT void JNICALL -Java_com_rtbishop_look4sat_feature_cw_FldigiNative_process(JNIEnv* env, jobject thiz, jlong handle, jfloatArray audio) { - cw* decoder = reinterpret_cast(handle); - if (!decoder) return; - - jsize len = env->GetArrayLength(audio); - jfloat* elements = env->GetFloatArrayElements(audio, nullptr); - if (!elements) return; - - // Convert float to double - double* buf = new double[len]; - for (jsize i = 0; i < len; i++) { - buf[i] = static_cast(elements[i]); - } - - decoder->rx_process(buf, len); - - delete[] buf; - env->ReleaseFloatArrayElements(audio, elements, JNI_ABORT); -} - -extern "C" JNIEXPORT jstring JNICALL -Java_com_rtbishop_look4sat_feature_cw_FldigiNative_getDecodedText(JNIEnv* env, jobject thiz, jlong handle) { - cw* decoder = reinterpret_cast(handle); - if (!decoder) return env->NewStringUTF(""); - - std::string text = decoder->get_rx_text(); - return env->NewStringUTF(text.c_str()); -} \ No newline at end of file diff --git a/feature/cw/src/main/java/com/rtbishop/look4sat/feature/cw/CwDecodeScreen.kt b/feature/cw/src/main/java/com/rtbishop/look4sat/feature/cw/CwDecodeScreen.kt index 5dc5b89d..c2387315 100644 --- a/feature/cw/src/main/java/com/rtbishop/look4sat/feature/cw/CwDecodeScreen.kt +++ b/feature/cw/src/main/java/com/rtbishop/look4sat/feature/cw/CwDecodeScreen.kt @@ -59,6 +59,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.constraintlayout.widget.ConstraintLayout +import com.ve3nea.morse_expert.MainActivity @Composable fun CwDecodeScreen(navigateUp: () -> Unit = {}) { @@ -66,8 +67,8 @@ fun CwDecodeScreen(navigateUp: () -> Unit = {}) { val activity = remember(context) { context as? Activity ?: error("CwDecodeScreen must be hosted in an Activity") } - // fldigi 解码器控制器; 每次进入页面新建实例 - val controller = remember { FldigiCwController() } + // 照搬的控制器(普通类, 非 Activity); 每次进入页面新建实例 + val controller = remember { MainActivity() } // 提前 inflate 原版布局, 供 AndroidView 与控制器 onCreate 共用同一根视图 val rootView = remember(context) { LayoutInflater.from(context).inflate(R.layout.activity_main, null) as ConstraintLayout diff --git a/feature/cw/src/main/java/com/rtbishop/look4sat/feature/cw/CwSettingsDialog.kt b/feature/cw/src/main/java/com/rtbishop/look4sat/feature/cw/CwSettingsDialog.kt index e002f365..ce817298 100644 --- a/feature/cw/src/main/java/com/rtbishop/look4sat/feature/cw/CwSettingsDialog.kt +++ b/feature/cw/src/main/java/com/rtbishop/look4sat/feature/cw/CwSettingsDialog.kt @@ -44,7 +44,7 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import com.rtbishop.look4sat.feature.cw.FldigiCwController +import com.ve3nea.morse_expert.MainActivity import kotlin.math.roundToInt /** 键名/默认值照搬原 Morse Expert(root_preferences.xml + SettingsActivity 逻辑)。 */ @@ -55,30 +55,6 @@ private const val DEFAULT_TEXT_FONT_SIZE = 18 private const val MIN_FONT_SIZE = 7 private const val MAX_FONT_SIZE = 99 -/** 颜色键名(照搬原 Morse Expert I2.b.f663b) */ -private val ColorKeys = arrayOf( - "bg_color", "text_color", "text_color_weak", - "call_color", "call_color_weak", - "cq_color", "cq_color_weak", - "rst_color", "rst_color_weak" -) - -/** 颜色默认值(照搬原 Morse Expert I2.b.f664d,ARGB int) */ -private val ColorDefaults = intArrayOf( - -3084048, -16777216, -5592406, - -65536, -30584, - -16776961, -7829249, - -65281, -30465 -) - -/** 颜色名称(照搬原 Morse Expert I2.b.c) */ -private val ColorNames = arrayOf( - "Background color", "Text color", "Text color, weak", - "Callsign color", "Callsign color, weak", - "CQ color", "CQ color, weak", - "RST color", "RST color, weak" -) - /** 预置色板(9 色, 3x3 网格);原 ColorPreferenceCompat 用第三方 colorpicker, 不引入。 */ private val PaletteColors = listOf( 0xFFD0F0F0.toInt(), 0xFF000000.toInt(), 0xFFFFFFFF.toInt(), @@ -94,7 +70,7 @@ private val PaletteColors = listOf( * 点击 OK 保存并调用 controller.onResume() 立即生效; Cancel/点外部仅关闭不保存。 */ @Composable -fun CwSettingsDialog(controller: FldigiCwController, onDismiss: () -> Unit) { +fun CwSettingsDialog(controller: MainActivity, onDismiss: () -> Unit) { val activity = controller.mActivity ?: return val prefs = remember(activity) { activity.getSharedPreferences(activity.packageName + "_preferences", Context.MODE_PRIVATE) @@ -110,7 +86,7 @@ fun CwSettingsDialog(controller: FldigiCwController, onDismiss: () -> Unit) { ) } var colorValues by remember { - mutableStateOf(IntArray(9) { i -> prefs.getInt(ColorKeys[i], ColorDefaults[i]) }) + mutableStateOf(IntArray(9) { i -> prefs.getInt(I2.b.f663b[i], I2.b.f664d[i]) }) } AlertDialog( @@ -148,7 +124,7 @@ fun CwSettingsDialog(controller: FldigiCwController, onDismiss: () -> Unit) { Text("Colors", style = MaterialTheme.typography.titleSmall) for (i in 0 until 9) { ColorSettingRow( - title = ColorNames[i], + title = I2.b.c[i], value = colorValues[i], onSelect = { selected -> colorValues = colorValues.copyOf().also { it[i] = selected } @@ -163,7 +139,7 @@ fun CwSettingsDialog(controller: FldigiCwController, onDismiss: () -> Unit) { editor.putString(KEY_MESSAGE_TYPE, messageType) editor.putInt(KEY_TEXT_FONT_SIZE, fontSize.roundToInt()) for (i in 0 until 9) { - editor.putInt(ColorKeys[i], colorValues[i]) + editor.putInt(I2.b.f663b[i], colorValues[i]) } editor.apply() // 原 SettingsActivity 返回时由 MainActivity.onResume() 重新读取全部设置; 照搬逻辑已就位 diff --git a/feature/cw/src/main/java/com/rtbishop/look4sat/feature/cw/FldigiCwController.kt b/feature/cw/src/main/java/com/rtbishop/look4sat/feature/cw/FldigiCwController.kt deleted file mode 100644 index 3a6e5798..00000000 --- a/feature/cw/src/main/java/com/rtbishop/look4sat/feature/cw/FldigiCwController.kt +++ /dev/null @@ -1,205 +0,0 @@ -package com.rtbishop.look4sat.feature.cw - -import android.Manifest -import android.app.Activity -import android.content.Context -import android.content.pm.PackageManager -import android.media.AudioFormat -import android.media.AudioRecord -import android.media.MediaRecorder -import android.view.View -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.isActive -import kotlinx.coroutines.launch - -/** - * fldigi CW 解码器控制器。 - * 替代 com.ve3nea.morse_expert.MainActivity,提供相同生命周期接口: - * onCreate / onResume / onPause / onDestroy / onPermissionGranted - * 内部使用 AudioRecord 采集麦克风,送入 fldigi 原生解码器。 - */ -class FldigiCwController { - - /** 兼容 CwSettingsDialog 对 controller.mActivity 的引用 */ - var mActivity: Activity? = null - private set - - private var nativeHandle: Long = 0L - private var audioRecord: AudioRecord? = null - private var isRunning = false - private var audioThread: Thread? = null - private val scope = CoroutineScope(Dispatchers.Main + Job()) - - private val _decodedText = MutableStateFlow("") - val decodedText: StateFlow = _decodedText.asStateFlow() - - // 轮询解码文本 - private var pollJob: Job? = null - - /** 创建解码器, 保存 Activity 引用。rootView 暂不处理(UI 由 AndroidView 管理)。 */ - fun onCreate(activity: Activity, rootView: View?) { - mActivity = activity - if (nativeHandle == 0L) { - nativeHandle = FldigiNative.create() - } - } - - /** 授予权限后启动录音和解码线程 */ - fun onPermissionGranted() { - startAudioCapture() - } - - /** 恢复录音和解码 */ - fun onResume() { - if (hasPermission()) { - startAudioCapture() - } - // 启动轮询 - pollJob?.cancel() - pollJob = scope.launch { - while (isActive) { - val text = FldigiNative.getDecodedText(nativeHandle) - if (text.isNotEmpty()) { - _decodedText.value += text - } - delay(100L) - } - } - } - - /** 暂停录音 */ - fun onPause() { - stopAudioCapture() - pollJob?.cancel() - pollJob = null - } - - /** 销毁解码器 */ - fun onDestroy() { - stopAudioCapture() - pollJob?.cancel() - if (nativeHandle != 0L) { - FldigiNative.destroy(nativeHandle) - nativeHandle = 0L - } - } - - /** 获取当前解码文本(供 Compose 读取) */ - fun getCurrentText(): String = _decodedText.value - - /** 清除解码文本 */ - fun clearText() { - _decodedText.value = "" - } - - // ── 兼容 MainActivity 接口(CwDecodeScreen 顶部按钮用)── - - /** 暂停/恢复解码 */ - fun togglePause() { - if (isRunning) { - stopAudioCapture() - } else { - startAudioCapture() - } - } - - /** 清除解码文本(= clearText) */ - fun clearDecoded() = clearText() - - /** 保存解码文本到文件。当前简单实现: 不落盘(可选扩展) */ - fun saveText() { - // 可选: 把 _decodedText.value 写入外部存储 - } - - /** 录音信号保存。占位实现 */ - fun recordSignals() { - // 可选扩展 - } - - /** 返回是否处理了返回键(占位,直接返回 false 让上层导航) */ - fun handleBackPress(): Boolean = false - - // ── 内部 ── - - private fun hasPermission(): Boolean { - val ctx = mActivity ?: return false - return ctx.checkSelfPermission(Manifest.permission.RECORD_AUDIO) == - PackageManager.PERMISSION_GRANTED - } - - private fun startAudioCapture() { - if (isRunning) return - val ctx = mActivity ?: return - if (!hasPermission()) return - - val sampleRate = 8000 // fldigi CW 解码器需要的采样率 - val bufferSize = AudioRecord.getMinBufferSize( - sampleRate, - AudioFormat.CHANNEL_IN_MONO, - AudioFormat.ENCODING_PCM_16BIT - ).coerceAtLeast(4096) - - try { - audioRecord = AudioRecord( - MediaRecorder.AudioSource.MIC, - sampleRate, - AudioFormat.CHANNEL_IN_MONO, - AudioFormat.ENCODING_PCM_16BIT, - bufferSize - ) - } catch (e: SecurityException) { - return - } - - val record = audioRecord ?: return - if (record.state != AudioRecord.STATE_INITIALIZED) { - record.release() - audioRecord = null - return - } - - record.startRecording() - isRunning = true - - // 16-bit PCM → float 转换送入解码器 - val shortBuf = ShortArray(4096) - val floatBuf = FloatArray(4096) - audioThread = Thread { - android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO) - while (isRunning && nativeHandle != 0L) { - val read = record.read(shortBuf, 0, shortBuf.size) - if (read > 0) { - // 转 float [-1.0, 1.0] - for (i in 0 until read) { - floatBuf[i] = shortBuf[i].toFloat() / 32768f - } - FldigiNative.process(nativeHandle, floatBuf.copyOf(read)) - } - } - }.apply { - name = "fldigi-cw-audio" - start() - } - } - - private fun stopAudioCapture() { - isRunning = false - audioThread?.join(500) - audioThread = null - try { - audioRecord?.apply { - if (recordingState == AudioRecord.RECORDSTATE_RECORDING) { - stop() - } - release() - } - } catch (_: Exception) { } - audioRecord = null - } -} \ No newline at end of file diff --git a/feature/cw/src/main/java/com/rtbishop/look4sat/feature/cw/FldigiNative.kt b/feature/cw/src/main/java/com/rtbishop/look4sat/feature/cw/FldigiNative.kt deleted file mode 100644 index 9541b6f2..00000000 --- a/feature/cw/src/main/java/com/rtbishop/look4sat/feature/cw/FldigiNative.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.rtbishop.look4sat.feature.cw - -/** - * JNI 绑定: fldigi CW 解码器原生库。 - * 对应 C++ 文件: fldigi_cw_jni.cpp - */ -object FldigiNative { - init { - System.loadLibrary("fldigi_cw") - } - - /** 创建解码器实例, 返回 native handle (long) */ - external fun create(): Long - - /** 销毁解码器 */ - external fun destroy(handle: Long) - - /** 送入 PCM 音频数据 (float[], mono, 8000Hz), 解码 */ - external fun process(handle: Long, audio: FloatArray) - - /** 获取并清空积压的解码文本, 返回空字符串表示无新输出 */ - external fun getDecodedText(handle: Long): String -} \ No newline at end of file diff --git a/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/TransceiversPage.kt b/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/TransceiversPage.kt index cdacc049..ee0d5d56 100644 --- a/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/TransceiversPage.kt +++ b/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/TransceiversPage.kt @@ -95,7 +95,7 @@ import com.rtbishop.look4sat.core.presentation.R import com.rtbishop.look4sat.core.presentation.formatFrequency import com.rtbishop.look4sat.core.presentation.infiniteMarquee import com.rtbishop.look4sat.feature.cw.R as CwR -import com.rtbishop.look4sat.feature.cw.FldigiCwController +import com.ve3nea.morse_expert.MainActivity import java.util.Locale import kotlin.time.Duration.Companion.milliseconds @@ -941,7 +941,7 @@ private fun CwDecoderPanel( val activity = remember(context) { context as? Activity ?: error("CwDecoderPanel must be hosted in an Activity") } - val controller = remember { FldigiCwController() } + val controller = remember { MainActivity() } val rootView = remember(context) { LayoutInflater.from(context).inflate(CwR.layout.activity_main, null) as ConstraintLayout }