@@ -70,11 +70,10 @@ aptdec-cli -i lut -l luts/WXtoImg-N18-HVC.png gqrx_20200527_115730_137914960.wav | |||||
### Arguments | ### Arguments | ||||
``` | ``` | ||||
-h, --help show a help message and exit | |||||
-i, --image=<str> set output image type (see below) | |||||
-e, --effect=<str> add an effect (see below) | |||||
-g, --gamma=<flt> gamma adjustment (1.0 = off) | |||||
-s, --satellite=<int> satellite ID, must be between 15, 18 or 19 or NORAD | |||||
-h, --help show this help message and exit | |||||
-i, --image=<str> set output image type (see the README for a list) | |||||
-e, --effect=<str> add an effect (see the README for a list) | |||||
-s, --satellite=<int> satellite ID, must be either NORAD or 15/18/19 | |||||
-l, --lut=<str> path to a LUT | -l, --lut=<str> path to a LUT | ||||
-o, --output=<str> path of output image | -o, --output=<str> path of output image | ||||
-r, --realtime decode in realtime | -r, --realtime decode in realtime | ||||
@@ -129,7 +128,7 @@ sudo apt install wget cmake make mingw-w64 git unzip | |||||
To build natively on Windows using MSVC, you will need: git, ninja and cmake. Then run: | To build natively on Windows using MSVC, you will need: git, ninja and cmake. Then run: | ||||
``` | ``` | ||||
.\build_windows.bat | |||||
./build_windows.bat | |||||
``` | ``` | ||||
If you only want to build libaptdec, libpng and libsndfile aren't needed. | If you only want to build libaptdec, libpng and libsndfile aren't needed. | ||||
@@ -110,7 +110,7 @@ int main(int argc, const char **argv) { | |||||
OPT_STRING('i', "image", &opts.type, "set output image type (see the README for a list)", NULL, 0, 0), | OPT_STRING('i', "image", &opts.type, "set output image type (see the README for a list)", NULL, 0, 0), | ||||
OPT_STRING('e', "effect", &opts.effects, "add an effect (see the README for a list)", NULL, 0, 0), | OPT_STRING('e', "effect", &opts.effects, "add an effect (see the README for a list)", NULL, 0, 0), | ||||
OPT_GROUP("Satellite options"), | OPT_GROUP("Satellite options"), | ||||
OPT_INTEGER('s', "satellite", &opts.satellite, "satellite ID, must be either NORAD or between 15 and 19", NULL, 0, 0), | |||||
OPT_INTEGER('s', "satellite", &opts.satellite, "satellite ID, must be either NORAD or 15/18/19", NULL, 0, 0), | |||||
OPT_GROUP("Paths"), | OPT_GROUP("Paths"), | ||||
OPT_STRING('l', "lut", &opts.lut, "path to a LUT", NULL, 0, 0), | OPT_STRING('l', "lut", &opts.lut, "path to a LUT", NULL, 0, 0), | ||||
OPT_STRING('o', "output", &opts.filename, "path of output image", NULL, 0, 0), | OPT_STRING('o', "output", &opts.filename, "path of output image", NULL, 0, 0), | ||||
@@ -454,7 +454,7 @@ static size_t callback(float *samples, size_t count, void *context) { | |||||
case 1: | case 1: | ||||
return sf_read_float(file->file, samples, count); | return sf_read_float(file->file, samples, count); | ||||
case 2: { | case 2: { | ||||
float _samples[count * 2]; | |||||
float _samples[APTDEC_BUFFER_SIZE * 2]; | |||||
size_t read = sf_read_float(file->file, _samples, count * 2); | size_t read = sf_read_float(file->file, _samples, count * 2); | ||||
for (size_t i = 0; i < count; i++) { | for (size_t i = 0; i < count; i++) { | ||||
@@ -22,7 +22,11 @@ | |||||
#include <stddef.h> | #include <stddef.h> | ||||
void error_noexit(const char *text); | void error_noexit(const char *text); | ||||
#ifdef _MSC_VER | |||||
void error(const char *text); | |||||
#else | |||||
__attribute__((noreturn)) void error(const char *text); | __attribute__((noreturn)) void error(const char *text); | ||||
#endif | |||||
void warning(const char *text); | void warning(const char *text); | ||||
int clamp_int(int x, int lo, int hi); | int clamp_int(int x, int lo, int hi); | ||||
@@ -1,36 +1,36 @@ | |||||
REM Build using Visual Studio 2019 on Windows | |||||
REM Additional tools needed: git, cmake and ninja | |||||
REM Build using MSVC on Windows | |||||
REM Requires: git, cmake and ninja | |||||
REM Build zlib | REM Build zlib | ||||
git clone -b v1.2.13 https://github.com/madler/zlib | |||||
cd zlib | |||||
mkdir build | |||||
cd build | |||||
cmake -G Ninja -DCMAKE_C_COMPILER="cl.exe" -DMSVC_TOOLSET_VERSION=190 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../../winpath .. | |||||
ninja install | |||||
cd ../../ | |||||
IF NOT EXIST zlib ( | |||||
git clone -b v1.2.13 https://github.com/madler/zlib | |||||
cd zlib | |||||
cmake -B build -G Ninja -DCMAKE_C_COMPILER="cl.exe" -DMSVC_TOOLSET_VERSION=190 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../winpath | |||||
cmake --build build -j4 | |||||
cmake --build build --target install | |||||
cd .. | |||||
) | |||||
REM Build libpng | REM Build libpng | ||||
git clone -b v1.6.39 https://github.com/glennrp/libpng | |||||
cd libpng | |||||
mkdir build | |||||
cd build | |||||
cmake -G Ninja -DCMAKE_C_COMPILER="cl.exe" -DMSVC_TOOLSET_VERSION=190 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../../winpath .. | |||||
ninja install | |||||
cd ../.. | |||||
IF NOT EXIST libpng ( | |||||
git clone -b v1.6.39 https://github.com/glennrp/libpng | |||||
cd libpng | |||||
cmake -B build -G Ninja -DCMAKE_C_COMPILER="cl.exe" -DMSVC_TOOLSET_VERSION=190 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../winpath -DPNG_STATIC=OFF -DPNG_EXECUTABLES=OFF -DPNG_TESTS=OFF | |||||
cmake --build build -j4 | |||||
cmake --build build --target install | |||||
cd .. | |||||
) | |||||
REM Build libsndfile - Could build Vorbis, FLAC and Opus first for extra support | |||||
git clone -b 1.1.0 https://github.com/libsndfile/libsndfile | |||||
cd libsndfile | |||||
mkdir build | |||||
cd build | |||||
cmake -G Ninja -DCMAKE_C_COMPILER="cl.exe" -DMSVC_TOOLSET_VERSION=190 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../../winpath .. | |||||
ninja install | |||||
cd ../.. | |||||
REM Build libsndfile, only with WAV support | |||||
IF NOT EXIST libsndfile ( | |||||
git clone -b 1.2.0 https://github.com/libsndfile/libsndfile | |||||
cd libsndfile | |||||
cmake -B build -G Ninja -DCMAKE_C_COMPILER="cl.exe" -DMSVC_TOOLSET_VERSION=190 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../winpath -BUILD_SHARED_LIBS=ON -DBUILD_EXAMPLES=OFF -DBUILD_PROGRAMS=OFF | |||||
cmake --build build -j4 | |||||
cmake --build build --target install | |||||
cd .. | |||||
) | |||||
REM Build aptdec | REM Build aptdec | ||||
mkdir winbuild | |||||
cd winbuild | |||||
cmake -G Ninja -DCMAKE_C_COMPILER="cl.exe" -DMSVC_TOOLSET_VERSION=190 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../winpath .. | |||||
ninja install | |||||
cd .. | |||||
cmake -B winbuild -G Ninja -DCMAKE_C_COMPILER="cl.exe" -DMSVC_TOOLSET_VERSION=190 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../winpath | |||||
cmake --build winbuil -j4 |
@@ -17,7 +17,7 @@ fi | |||||
# Build libpng from source | # Build libpng from source | ||||
if [ ! -d "libpng" ]; then | if [ ! -d "libpng" ]; then | ||||
git clone --depth 1 -b v1.6.39 https://github.com/glennrp/libpng && cd libpng | git clone --depth 1 -b v1.6.39 https://github.com/glennrp/libpng && cd libpng | ||||
cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchain-mingw32.cmake -DCMAKE_INSTALL_PREFIX=$TEMP_PATH | |||||
cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchain-mingw32.cmake -DCMAKE_INSTALL_PREFIX=$TEMP_PATH -DPNG_STATIC=OFF -DPNG_EXECUTABLES=OFF -DPNG_TESTS=OFF | |||||
cmake --build build -j$(nproc) | cmake --build build -j$(nproc) | ||||
cmake --build build --target install | cmake --build build --target install | ||||
cd .. | cd .. | ||||
@@ -27,7 +27,6 @@ | |||||
#include "util.h" | #include "util.h" | ||||
#include "algebra.h" | #include "algebra.h" | ||||
#define BUFFER_SIZE 16384 | |||||
#define LOW_PASS_SIZE 101 | #define LOW_PASS_SIZE 101 | ||||
#define CARRIER_FREQ 2400.0f | #define CARRIER_FREQ 2400.0f | ||||
@@ -113,7 +112,7 @@ aptdec_t *aptdec_init(float sample_rate) { | |||||
} | } | ||||
// Hilbert transform | // Hilbert transform | ||||
apt->hilbert = fir_init(BUFFER_SIZE, 31); | |||||
apt->hilbert = fir_init(APTDEC_BUFFER_SIZE, 31); | |||||
if (apt->hilbert == NULL) { | if (apt->hilbert == NULL) { | ||||
free(apt->pll); | free(apt->pll); | ||||
free(apt); | free(apt); | ||||
@@ -163,18 +162,18 @@ static int am_demod(aptdec_t *apt, float *out, size_t count, aptdec_callback_t c | |||||
} | } | ||||
static int get_pixels(aptdec_t *apt, float *out, size_t count, aptdec_callback_t callback, void *context) { | static int get_pixels(aptdec_t *apt, float *out, size_t count, aptdec_callback_t callback, void *context) { | ||||
static float buffer[BUFFER_SIZE]; | |||||
static size_t n = BUFFER_SIZE; | |||||
static float buffer[APTDEC_BUFFER_SIZE]; | |||||
static size_t n = APTDEC_BUFFER_SIZE; | |||||
static float offset = 0.0; | static float offset = 0.0; | ||||
float ratio = apt->sample_rate / (4160.0f * apt->sync_frequency); | float ratio = apt->sample_rate / (4160.0f * apt->sync_frequency); | ||||
for (size_t i = 0; i < count; i++) { | for (size_t i = 0; i < count; i++) { | ||||
// Get more samples if there are less than `LOW_PASS_SIZE` available | // Get more samples if there are less than `LOW_PASS_SIZE` available | ||||
if (n + LOW_PASS_SIZE > BUFFER_SIZE) { | |||||
memcpy(buffer, &buffer[n], (BUFFER_SIZE-n) * sizeof(float)); | |||||
if (n + LOW_PASS_SIZE > APTDEC_BUFFER_SIZE) { | |||||
memcpy(buffer, &buffer[n], (APTDEC_BUFFER_SIZE-n) * sizeof(float)); | |||||
size_t read = am_demod(apt, &buffer[BUFFER_SIZE-n], n, callback, context); | |||||
size_t read = am_demod(apt, &buffer[APTDEC_BUFFER_SIZE-n], n, callback, context); | |||||
if (read != n) { | if (read != n) { | ||||
return i; | return i; | ||||
} | } | ||||
@@ -138,7 +138,7 @@ int apt_crop(apt_image_t *img) { | |||||
const float sync_pattern[] = {-1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, | const float sync_pattern[] = {-1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, | ||||
1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 0}; | 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 0}; | ||||
float spc_rows[img->rows]; | |||||
float *spc_rows = (float *)malloc(img->rows * sizeof(float)); | |||||
int startCrop = 0; | int startCrop = 0; | ||||
int endCrop = img->rows; | int endCrop = img->rows; | ||||
@@ -171,5 +171,6 @@ int apt_crop(apt_image_t *img) { | |||||
// Remove the noisy rows at start | // Remove the noisy rows at start | ||||
memmove(img->data, &img->data[startCrop * APT_IMG_WIDTH], img->rows * APT_IMG_WIDTH * sizeof(float)); | memmove(img->data, &img->data[startCrop * APT_IMG_WIDTH], img->rows * APT_IMG_WIDTH * sizeof(float)); | ||||
free(spc_rows); | |||||
return startCrop; | return startCrop; | ||||
} | } |
@@ -98,7 +98,11 @@ complexf_t hilbert_transform(const float *in, const float *taps, size_t len) { | |||||
} | } | ||||
float interpolating_convolve(const float *in, const float *taps, size_t len, float offset) { | float interpolating_convolve(const float *in, const float *taps, size_t len, float offset) { | ||||
#ifdef _MSC_VER | |||||
float *_taps = (float *)_alloca(len * sizeof(float)); | |||||
#else | |||||
float _taps[len]; | float _taps[len]; | ||||
#endif | |||||
for (size_t i = 0; i < len; i++) { | for (size_t i = 0; i < len; i++) { | ||||
float next = (i == len-1) ? 0.0f : taps[i+1]; | float next = (i == len-1) ? 0.0f : taps[i+1]; | ||||
@@ -38,7 +38,7 @@ apt_image_t apt_image_clone(apt_image_t img) { | |||||
static void decode_telemetry(const float *data, size_t rows, size_t offset, float *wedges) { | static void decode_telemetry(const float *data, size_t rows, size_t offset, float *wedges) { | ||||
// Calculate row average | // Calculate row average | ||||
float telemetry_rows[rows]; | |||||
float *telemetry_rows = (float *)malloc(rows * sizeof(float)); | |||||
for (size_t y = 0; y < rows; y++) { | for (size_t y = 0; y < rows; y++) { | ||||
telemetry_rows[y] = meanf(&data[y*APT_IMG_WIDTH + offset + APT_CH_WIDTH], APT_TELEMETRY_WIDTH); | telemetry_rows[y] = meanf(&data[y*APT_IMG_WIDTH + offset + APT_CH_WIDTH], APT_TELEMETRY_WIDTH); | ||||
} | } | ||||
@@ -74,10 +74,12 @@ static void decode_telemetry(const float *data, size_t rows, size_t offset, floa | |||||
for (size_t i = 0; i < APT_FRAME_WEDGES; i++) { | for (size_t i = 0; i < APT_FRAME_WEDGES; i++) { | ||||
wedges[i] = meanf(&telemetry_rows[best_frame + i*APT_WEDGE_HEIGHT], APT_WEDGE_HEIGHT); | wedges[i] = meanf(&telemetry_rows[best_frame + i*APT_WEDGE_HEIGHT], APT_WEDGE_HEIGHT); | ||||
} | } | ||||
free(telemetry_rows); | |||||
} | } | ||||
static float average_spc(apt_image_t *img, size_t offset) { | static float average_spc(apt_image_t *img, size_t offset) { | ||||
float rows[img->rows]; | |||||
float *rows = (float *)malloc(img->rows * sizeof(float)); | |||||
float average = 0.0f; | float average = 0.0f; | ||||
for (size_t y = 0; y < img->rows; y++) { | for (size_t y = 0; y < img->rows; y++) { | ||||
float row_average = 0.0f; | float row_average = 0.0f; | ||||
@@ -100,6 +102,7 @@ static float average_spc(apt_image_t *img, size_t offset) { | |||||
} | } | ||||
} | } | ||||
free(rows); | |||||
return weighted_average / (float)n; | return weighted_average / (float)n; | ||||
} | } | ||||
@@ -64,6 +64,8 @@ extern "C" { | |||||
// Number of rows needed for apt_normalize to (reliably) work | // Number of rows needed for apt_normalize to (reliably) work | ||||
#define APTDEC_NORMALIZE_ROWS (APT_FRAME_LEN * 2) | #define APTDEC_NORMALIZE_ROWS (APT_FRAME_LEN * 2) | ||||
// Maximum amount of samples that will be requested from aptdec_callback_t | |||||
#define APTDEC_BUFFER_SIZE 16384 | |||||
// Channel 1: visible (0.58-0.68 um) | // Channel 1: visible (0.58-0.68 um) | ||||
// Channel 2: near-IR (0.725-1.0 um) | // Channel 2: near-IR (0.725-1.0 um) | ||||
@@ -115,7 +117,7 @@ typedef size_t (*aptdec_callback_t)(float *samples, size_t count, void *context) | |||||
// Clone an apt_image_t struct | // Clone an apt_image_t struct | ||||
// Useful for calibration | // Useful for calibration | ||||
apt_image_t apt_image_clone(apt_image_t img); | |||||
APTDEC_API apt_image_t apt_image_clone(apt_image_t img); | |||||
// Returns version of libaptdec in git tag format | // Returns version of libaptdec in git tag format | ||||
// i.e. v2.0.0 or v2.0.0-1-xxxxxx | // i.e. v2.0.0 or v2.0.0-1-xxxxxx | ||||
@@ -159,8 +161,8 @@ static const apt_region_t APT_REGION_CHA_FULL = { 0, APT_IMG_WIDTH | |||||
static const apt_region_t APT_REGION_CHB_FULL = { APT_IMG_WIDTH/2, APT_IMG_WIDTH/2 }; | static const apt_region_t APT_REGION_CHB_FULL = { APT_IMG_WIDTH/2, APT_IMG_WIDTH/2 }; | ||||
static const apt_region_t APT_REGION_FULL = { 0, APT_IMG_WIDTH }; | static const apt_region_t APT_REGION_FULL = { 0, APT_IMG_WIDTH }; | ||||
extern const uint32_t temperature_gradient[256]; | |||||
extern const uint32_t precipitation_gradient[58]; | |||||
APTDEC_API extern const uint32_t temperature_gradient[256]; | |||||
APTDEC_API extern const uint32_t precipitation_gradient[58]; | |||||
#ifdef __cplusplus | #ifdef __cplusplus | ||||
} | } | ||||