diff --git a/README.md b/README.md index 1d8acab..d7618bf 100644 --- a/README.md +++ b/README.md @@ -70,11 +70,10 @@ aptdec-cli -i lut -l luts/WXtoImg-N18-HVC.png gqrx_20200527_115730_137914960.wav ### Arguments ``` --h, --help show a help message and exit --i, --image= set output image type (see below) --e, --effect= add an effect (see below) --g, --gamma= gamma adjustment (1.0 = off) --s, --satellite= satellite ID, must be between 15, 18 or 19 or NORAD +-h, --help show this help message and exit +-i, --image= set output image type (see the README for a list) +-e, --effect= add an effect (see the README for a list) +-s, --satellite= satellite ID, must be either NORAD or 15/18/19 -l, --lut= path to a LUT -o, --output= path of output image -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: ``` -.\build_windows.bat +./build_windows.bat ``` If you only want to build libaptdec, libpng and libsndfile aren't needed. diff --git a/aptdec-cli/main.c b/aptdec-cli/main.c index 7441354..316a700 100644 --- a/aptdec-cli/main.c +++ b/aptdec-cli/main.c @@ -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('e', "effect", &opts.effects, "add an effect (see the README for a list)", NULL, 0, 0), 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_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), @@ -454,7 +454,7 @@ static size_t callback(float *samples, size_t count, void *context) { case 1: return sf_read_float(file->file, samples, count); case 2: { - float _samples[count * 2]; + float _samples[APTDEC_BUFFER_SIZE * 2]; size_t read = sf_read_float(file->file, _samples, count * 2); for (size_t i = 0; i < count; i++) { diff --git a/aptdec-cli/util.h b/aptdec-cli/util.h index c8ab688..1ab9984 100644 --- a/aptdec-cli/util.h +++ b/aptdec-cli/util.h @@ -22,7 +22,11 @@ #include void error_noexit(const char *text); +#ifdef _MSC_VER +void error(const char *text); +#else __attribute__((noreturn)) void error(const char *text); +#endif void warning(const char *text); int clamp_int(int x, int lo, int hi); diff --git a/build_windows.bat b/build_windows.bat index 259beaa..3f995cf 100644 --- a/build_windows.bat +++ b/build_windows.bat @@ -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 -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 -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 -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 diff --git a/build_windows.sh b/build_windows.sh index 8ec2a7d..151524c 100755 --- a/build_windows.sh +++ b/build_windows.sh @@ -17,7 +17,7 @@ fi # Build libpng from source if [ ! -d "libpng" ]; then 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 --target install cd .. diff --git a/libaptdec/dsp.c b/libaptdec/dsp.c index 3c5f486..59c969c 100644 --- a/libaptdec/dsp.c +++ b/libaptdec/dsp.c @@ -27,7 +27,6 @@ #include "util.h" #include "algebra.h" -#define BUFFER_SIZE 16384 #define LOW_PASS_SIZE 101 #define CARRIER_FREQ 2400.0f @@ -113,7 +112,7 @@ aptdec_t *aptdec_init(float sample_rate) { } // Hilbert transform - apt->hilbert = fir_init(BUFFER_SIZE, 31); + apt->hilbert = fir_init(APTDEC_BUFFER_SIZE, 31); if (apt->hilbert == NULL) { free(apt->pll); 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 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; float ratio = apt->sample_rate / (4160.0f * apt->sync_frequency); for (size_t i = 0; i < count; i++) { // 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) { return i; } diff --git a/libaptdec/effects.c b/libaptdec/effects.c index f8eff14..e48e584 100644 --- a/libaptdec/effects.c +++ b/libaptdec/effects.c @@ -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, 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 endCrop = img->rows; @@ -171,5 +171,6 @@ int apt_crop(apt_image_t *img) { // Remove the noisy rows at start memmove(img->data, &img->data[startCrop * APT_IMG_WIDTH], img->rows * APT_IMG_WIDTH * sizeof(float)); + free(spc_rows); return startCrop; } diff --git a/libaptdec/filter.c b/libaptdec/filter.c index e45fbf8..732d741 100644 --- a/libaptdec/filter.c +++ b/libaptdec/filter.c @@ -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) { +#ifdef _MSC_VER + float *_taps = (float *)_alloca(len * sizeof(float)); +#else float _taps[len]; +#endif for (size_t i = 0; i < len; i++) { float next = (i == len-1) ? 0.0f : taps[i+1]; diff --git a/libaptdec/image.c b/libaptdec/image.c index 7093563..5982c7d 100644 --- a/libaptdec/image.c +++ b/libaptdec/image.c @@ -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) { // Calculate row average - float telemetry_rows[rows]; + float *telemetry_rows = (float *)malloc(rows * sizeof(float)); for (size_t y = 0; y < rows; y++) { 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++) { 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) { - float rows[img->rows]; + float *rows = (float *)malloc(img->rows * sizeof(float)); float average = 0.0f; for (size_t y = 0; y < img->rows; y++) { 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; } diff --git a/libaptdec/include/aptdec.h b/libaptdec/include/aptdec.h index 669537c..9d3cc5b 100644 --- a/libaptdec/include/aptdec.h +++ b/libaptdec/include/aptdec.h @@ -64,6 +64,8 @@ extern "C" { // Number of rows needed for apt_normalize to (reliably) work #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 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 // 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 // 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_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 }