From dc3c02c76d9f3877afd8072443d33f3d0662a305 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Tue, 16 Feb 2021 16:47:49 +0000 Subject: [PATCH 01/14] Add support for building a shared library (libaptdec). Exported functions and types prefixed with apt_ Callback added for getsample, instead of calling named function. Allow library to be built without libpng or libsndfile. Add support for building with MSVC on Windows. Fix a few MSVC compiler warnings. Fix nonlinear radiance correction for NOAA19. --- CMakeLists.txt | 75 +++++++++++++++++++++++---------- README.md | 9 +++- build_windows.bat | 36 ++++++++++++++++ build_windows.sh | 3 ++ src/apt.h | 67 +++++++++++++++++++++++++++++ src/color.c | 9 ++-- src/color.h | 6 --- src/common.h | 13 +----- src/dsp.c | 23 +++++----- src/filter.c | 4 +- src/image.c | 44 ++++++++++---------- src/image.h | 9 +--- src/main.c | 70 ++++++++++++++++++++----------- src/pngio.c | 44 ++++++++++---------- src/pngio.h | 14 +++---- src/satcal.h | 104 +++++++++++++++++++++++----------------------- 16 files changed, 335 insertions(+), 195 deletions(-) create mode 100644 build_windows.bat create mode 100644 src/apt.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 19bec16..53b01b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,33 +2,53 @@ cmake_minimum_required (VERSION 3.0.0) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") project(aptdec) -file(GLOB_RECURSE C_SOURCE_FILES src/*.c src/libs/*.c) -add_executable(aptdec ${C_SOURCE_FILES}) + +# libpng +find_package(PNG) + +# libsndfile +find_package(LibSndFile) + +set(LIB_C_SOURCE_FILES src/color.c src/dsp.c src/filter.c src/image.c src/libs/reg.c src/libs/median.c) +set(EXE_C_SOURCE_FILES src/main.c src/pngio.c src/libs/argparse.c) +set(LIB_C_HEADER_FILES src/apt.h) + +add_library(libaptdec SHARED ${LIB_C_SOURCE_FILES}) add_compile_definitions(PALETTE_DIR="../palettes") -# Math -target_link_libraries(aptdec PRIVATE m) +if (PNG_FOUND AND LIBSNDFILE_FOUND) + add_executable(aptdec ${EXE_C_SOURCE_FILES}) + target_link_libraries(aptdec PRIVATE libaptdec) + target_link_libraries(aptdec PRIVATE PNG::PNG) + target_link_libraries(aptdec PRIVATE ${LIBSNDFILE_LIBRARY}) + if (CLANG OR GCC) + # Math + target_link_libraries(aptdec PRIVATE m) -# Throw errors on warnings on release builds -if(CMAKE_BUILD_TYPE MATCHES "Release") - target_compile_options(aptdec PRIVATE -Wall -Wextra -pedantic -Wno-missing-field-initializers -Werror) + # Throw errors on warnings on release builds + if(CMAKE_BUILD_TYPE MATCHES "Release") + target_compile_options(aptdec PRIVATE -Wall -Wextra -pedantic -Wno-missing-field-initializers -Werror) + else() + target_compile_options(aptdec PRIVATE -Wall -Wextra -pedantic) + endif() + elseif (MSVC) + target_compile_options(aptdec PRIVATE /D_CRT_SECURE_NO_WARNINGS=1) + endif() else() - target_compile_options(aptdec PRIVATE -Wall -Wextra -pedantic) + MESSAGE(STATUS "WARNING: Only building libaptdec, as not all of the required libraries were found.") endif() -# libpng -target_link_libraries(aptdec PRIVATE PNG::PNG) -if(WIN32 AND NOT MINGW) - find_package(PNG CONFIG REQUIRED) -else() - find_package(PNG REQUIRED) +if (CLANG OR CGCC) + if(CMAKE_BUILD_TYPE MATCHES "Release") + target_compile_options(libaptdec PRIVATE -Wall -Wextra -pedantic -Wno-missing-field-initializers -Werror) + else() + target_compile_options(libaptdec PRIVATE -Wall -Wextra -pedantic) + endif() +elseif (MSVC) + target_compile_options(libaptdec PRIVATE /D_CRT_SECURE_NO_WARNINGS=1) endif() -# libsndfile -find_package(LibSndFile REQUIRED) -target_link_libraries(aptdec PRIVATE ${LIBSNDFILE_LIBRARY}) - # TODO: get this from git set(PROJECT_VERSION "1.7.0") @@ -45,16 +65,25 @@ IF(NOT WIN32) set(CPACK_GENERATOR "DEB;TGZ") set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}.${CMAKE_SYSTEM_PROCESSOR}") - install(TARGETS aptdec DESTINATION "bin/") - install(DIRECTORY "${PROJECT_SOURCE_DIR}/palettes/" DESTINATION "palettes/") + if (TARGET aptdec) + install(TARGETS aptdec DESTINATION "bin/") + install(DIRECTORY "${PROJECT_SOURCE_DIR}/palettes/" DESTINATION "palettes/") + endif() + + install(TARGETS libaptdec LIBRARY DESTINATION lib) + install(FILES ${LIB_C_HEADER_FILES} DESTINATION include/apt ) else() #set(CPACK_GENERATOR "ZIP;NSIS") set(CPACK_GENERATOR "ZIP") set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") - install(TARGETS aptdec DESTINATION "bin/") - file(GLOB_RECURSE DLLS *.dll) - install(FILES ${DLLS} DESTINATION "bin/") + if (TARGET aptdec) + install(TARGETS aptdec DESTINATION "bin/") + file(GLOB_RECURSE DLLS *.dll) + install(FILES ${DLLS} DESTINATION "bin/") + endif() + install(TARGETS libaptdec DESTINATION "bin/") + install(FILES ${LIB_C_HEADER_FILES} DESTINATION include/apt ) install(DIRECTORY "${PROJECT_SOURCE_DIR}/palettes/" DESTINATION "palettes/") endif() diff --git a/README.md b/README.md index f1b6ce3..b6a3745 100644 --- a/README.md +++ b/README.md @@ -129,11 +129,18 @@ cmake .. make ``` -Since CMake is now being used for building, windows support has come. You can build for windows with the `build_windows.sh` script, you will need the following: +You can cross build for Windows from Linux with the `build_windows.sh` script, you will need the following: ``` sudo apt install wget cmake make mingw-w64 git unzip ``` +To build natively on Windows using MSVC, you will also need: git, ninja and cmake. Then run: +``` +.\build_windows.bat +``` + +If you just wish to build libaptdec on Windows, libpng and libsndfile aren't needed. + ## Further Reading [User's Guide for Building and Operating diff --git a/build_windows.bat b/build_windows.bat new file mode 100644 index 0000000..94b9662 --- /dev/null +++ b/build_windows.bat @@ -0,0 +1,36 @@ +# Build using Visual Studio 2019 on Windows +# Additional tools needed: git, cmake and ninja + +# Build zlib +git clone 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 ../../ + +# Build libpng +git clone 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 ../.. + +# Build libsndfile - Could build Vorbis, FLAC and Opus first for extra support +git clone https://github.com/libsndfile/libsndfile.git +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 ../.. + +# 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 ../.. diff --git a/build_windows.sh b/build_windows.sh index 33fb150..4cb578a 100755 --- a/build_windows.sh +++ b/build_windows.sh @@ -1,3 +1,6 @@ +#!/bin/bash +# Cross compile for Windows from Linux + TEMP_PATH="$(pwd)/winpath" set -e diff --git a/src/apt.h b/src/apt.h new file mode 100644 index 0000000..f5e03ca --- /dev/null +++ b/src/apt.h @@ -0,0 +1,67 @@ +/* + * This file is part of Aptdec. + * Copyright (c) 2004-2009 Thierry Leconte (F4DWV), Xerbo (xerbo@protonmail.com) 2019-2020 + * Copyright (c) 2021 Jon Beniston (M7RCE) + * + * Aptdec is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef APT_H +#define APT_H + +#if defined (__GNUC__) && (__GNUC__ >= 4) +#define APT_API __attribute__((visibility("default"))) +#elif defined (_MSC_VER) +#define APT_API __declspec(dllexport) +#else +#define APT_API +#endif + +// Maximum height of an APT image in number of scanlines +#define APT_MAX_HEIGHT 3000 + +// apt_getpixelrow callback function to get audio samples +typedef int (*apt_getsample_t)(float *samples, int count); + +typedef struct { + float *prow[APT_MAX_HEIGHT]; // Row buffers + int nrow; // Number of rows + int zenith; // Row in image where satellite reaches peak elevation + int chA, chB; // ID of each channel + char name[256]; // Stripped filename + char *palette; // Filename of palette +} apt_image_t; + +typedef struct { + float r, g, b; +} apt_rgb_t; + +int APT_API apt_init(double sample_rate); +int APT_API apt_getpixelrow(float *pixelv, int nrow, int *zenith, int reset, apt_getsample_t getsample); + +void APT_API apt_histogramEqualise(float **prow, int nrow, int offset, int width); +void APT_API apt_linearEnhance(float **prow, int nrow, int offset, int width); +int APT_API apt_calibrate(float **prow, int nrow, int offset, int width) ; +void APT_API apt_denoise(float **prow, int nrow, int offset, int width); +void APT_API apt_flipImage(apt_image_t *img, int width, int offset); +int APT_API apt_cropNoise(apt_image_t *img); + +apt_rgb_t APT_API apt_applyPalette(char *palette, int val); +apt_rgb_t APT_API apt_RGBcomposite(apt_rgb_t top, float top_a, apt_rgb_t bottom, float bottom_a); + +char APT_API apt_TempPalette[256*3]; +char APT_API apt_PrecipPalette[58*3]; + +#endif diff --git a/src/color.c b/src/color.c index dda501c..c49bade 100644 --- a/src/color.c +++ b/src/color.c @@ -17,18 +17,19 @@ * */ +#include "apt.h" #include "color.h" -rgb_t applyPalette(char *palette, int val){ - return (rgb_t){ +apt_rgb_t apt_applyPalette(char *palette, int val){ + return (apt_rgb_t){ palette[(int)CLIP(val, 0, 255)*3 + 0], palette[(int)CLIP(val, 0, 255)*3 + 1], palette[(int)CLIP(val, 0, 255)*3 + 2] }; } -rgb_t RGBcomposite(rgb_t top, float top_a, rgb_t bottom, float bottom_a){ - return (rgb_t){ +apt_rgb_t apt_RGBcomposite(apt_rgb_t top, float top_a, apt_rgb_t bottom, float bottom_a){ + return (apt_rgb_t){ MCOMPOSITE(top.r, top_a, bottom.r, bottom_a), MCOMPOSITE(top.g, top_a, bottom.g, bottom_a), MCOMPOSITE(top.b, top_a, bottom.b, bottom_a) diff --git a/src/color.h b/src/color.h index d6a4307..6441fb2 100644 --- a/src/color.h +++ b/src/color.h @@ -1,9 +1,3 @@ #include "common.h" #define MCOMPOSITE(m1, a1, m2, a2) (m1*a1 + m2*a2*(1-a1)) - -rgb_t applyPalette(char *palette, int val); -rgb_t RGBcomposite(rgb_t top, float top_a, rgb_t bottom, float bottom_a); - -extern char TempPalette[256*3]; -extern char PrecipPalette[58*3]; diff --git a/src/common.h b/src/common.h index 6f36d29..08e4834 100644 --- a/src/common.h +++ b/src/common.h @@ -19,7 +19,6 @@ // Constants #define VERSION "Aptdec; (c) 2004-2009 Thierry Leconte F4DWV, Xerbo (xerbo@protonmail.com) 2019-2020" -#define MAX_HEIGHT 3000 // Useful macros #define CLIP(v, lo, hi) (v > hi ? hi : (v > lo ? v : lo)) @@ -28,17 +27,6 @@ // Typedefs #ifndef STRUCTS_DEFINED #define STRUCTS_DEFINED -typedef struct { - float r, g, b; -} rgb_t; -typedef struct { - float *prow[MAX_HEIGHT]; // Row buffers - int nrow; // Number of rows - int zenith; // Row in image where satellite reaches peak elevation - int chA, chB; // ID of each channel - char name[256]; // Stripped filename - char *palette; // Filename of palette -} image_t; typedef struct { char *type; // Output image type char *effects; // Effects on the image @@ -70,4 +58,5 @@ enum effects { Linear_Equalise='l', Crop_Noise='c' }; + #endif diff --git a/src/dsp.c b/src/dsp.c index c567863..188f44c 100755 --- a/src/dsp.c +++ b/src/dsp.c @@ -22,6 +22,7 @@ #include #include +#include "apt.h" #include "filter.h" // In case your C compiler is so old that Pi hadn't been invented yet @@ -40,8 +41,6 @@ #define RSMULT 15 #define Fi (Fp * RSMULT) -extern int getsample(float *inbuff, int count); - static double Fe; static double offset = 0.0; @@ -51,7 +50,7 @@ static double FreqOsc; static double K1, K2; // Check the sample rate and calculate some constants -int init_dsp(double F) { +int apt_init(double F) { if(F > Fi) return 1; if(F < Fp) return -1; Fe = F; @@ -132,7 +131,7 @@ static double pll(double I, double Q) { } // Convert samples into pixels -static int getamp(double *ampbuff, int count) { +static int getamp(double *ampbuff, int count, apt_getsample_t getsample) { static float inbuff[BLKIN]; static int idxin = 0; static int nin = 0; @@ -169,7 +168,7 @@ static int getamp(double *ampbuff, int count) { } // Sub-pixel offsetting + FIR compensation -int getpixelv(float *pvbuff, int count) { +int getpixelv(float *pvbuff, int count, apt_getsample_t getsample) { // Amplitude buffer static double ampbuff[BLKAMP]; static int nam = 0; @@ -179,7 +178,7 @@ int getpixelv(float *pvbuff, int count) { // Gaussian resampling factor mult = (double) Fi / Fe * FreqLine; - int m = RSFilterLen / mult + 1; + int m = (int)(RSFilterLen / mult + 1); for (int n = 0; n < count; n++) { int shift; @@ -188,14 +187,14 @@ int getpixelv(float *pvbuff, int count) { int res; memmove(ampbuff, &(ampbuff[idxam]), nam * sizeof(double)); idxam = 0; - res = getamp(&(ampbuff[nam]), BLKAMP - nam); + res = getamp(&(ampbuff[nam]), BLKAMP - nam, getsample); nam += res; if (nam < m) return n; } // Gaussian FIR compensation filter - pvbuff[n] = rsfir(&(ampbuff[idxam]), rsfilter, RSFilterLen, offset, mult) * mult * 256.0; + pvbuff[n] = (float)(rsfir(&(ampbuff[idxam]), rsfilter, RSFilterLen, offset, mult) * mult * 256.0); shift = ((int) floor((RSMULT - offset) / mult)) + 1; offset = shift * mult + offset - RSMULT; @@ -208,7 +207,7 @@ int getpixelv(float *pvbuff, int count) { } // Get an entire row of pixels, aligned with sync markers -int getpixelrow(float *pixelv, int nrow, int *zenith, int reset) { +int apt_getpixelrow(float *pixelv, int nrow, int *zenith, int reset, apt_getsample_t getsample) { static float pixels[PixelLine + SyncFilterLen]; static int npv; static int synced = 0; @@ -226,7 +225,7 @@ int getpixelrow(float *pixelv, int nrow, int *zenith, int reset) { // Get the sync line if (npv < SyncFilterLen + 2) { - res = getpixelv(&(pixelv[npv]), SyncFilterLen + 2 - npv); + res = getpixelv(&(pixelv[npv]), SyncFilterLen + 2 - npv, getsample); npv += res; if (npv < SyncFilterLen + 2) return 0; @@ -257,7 +256,7 @@ int getpixelrow(float *pixelv, int nrow, int *zenith, int reset) { static int lastmshift; if (npv < PixelLine + SyncFilterLen) { - res = getpixelv(&(pixelv[npv]), PixelLine + SyncFilterLen - npv); + res = getpixelv(&(pixelv[npv]), PixelLine + SyncFilterLen - npv, getsample); npv += res; if (npv < PixelLine + SyncFilterLen) return 0; @@ -295,7 +294,7 @@ int getpixelrow(float *pixelv, int nrow, int *zenith, int reset) { // Get the rest of this row if (npv < PixelLine) { - res = getpixelv(&(pixelv[npv]), PixelLine - npv); + res = getpixelv(&(pixelv[npv]), PixelLine - npv, getsample); npv += res; if (npv < PixelLine) return 0; diff --git a/src/filter.c b/src/filter.c index d850fd0..dbc1d71 100755 --- a/src/filter.c +++ b/src/filter.c @@ -27,7 +27,7 @@ float fir(float *buff, const float *coeff, const int len) { for (int i = 0; i < len; i++) { r += buff[i] * coeff[i]; } - return r; + return (float)r; } /* IQ finite impulse response @@ -61,5 +61,5 @@ float rsfir(double *buff, const float *coeff, const int len, const double offset alpha = n - k; out += buff[i] * (coeff[k] * (1.0 - alpha) + coeff[k + 1] * alpha); } - return out; + return (float)out; } diff --git a/src/image.c b/src/image.c index 05fb2a4..11f9e27 100644 --- a/src/image.c +++ b/src/image.c @@ -19,10 +19,10 @@ #include #include -#include #include #include +#include "apt.h" #include "offsets.h" #include "libs/reg.h" #include "image.h" @@ -55,7 +55,7 @@ static double rgcal(float x, rgparam_t *rgpr) { static double tele[16]; static double Cs; -void histogramEqualise(float **prow, int nrow, int offset, int width){ +void apt_histogramEqualise(float **prow, int nrow, int offset, int width){ // Plot histogram int histogram[256] = { 0 }; for(int y = 0; y < nrow; y++) @@ -73,13 +73,13 @@ void histogramEqualise(float **prow, int nrow, int offset, int width){ int area = nrow * width; for(int y = 0; y < nrow; y++){ for(int x = 0; x < width; x++){ - int k = prow[y][x+offset]; - prow[y][x+offset] = (256.0/area) * cf[k]; + int k = (int)prow[y][x+offset]; + prow[y][x+offset] = (256.0f/area) * cf[k]; } } } -void linearEnhance(float **prow, int nrow, int offset, int width){ +void apt_linearEnhance(float **prow, int nrow, int offset, int width){ // Plot histogram int histogram[256] = { 0 }; for(int y = 0; y < nrow; y++) @@ -98,8 +98,8 @@ void linearEnhance(float **prow, int nrow, int offset, int width){ // Stretch the brightness into the new range for(int y = 0; y < nrow; y++){ for(int x = 0; x < width; x++){ - prow[y][x+offset] = (prow[y][x+offset]-min) / (max-min) * 255.0; - prow[y][x+offset] = CLIP(prow[y][x+offset], 0.0, 255.0); + prow[y][x+offset] = (prow[y][x+offset]-min) / (max-min) * 255.0f; + prow[y][x+offset] = CLIP(prow[y][x+offset], 0.0f, 255.0f); } } } @@ -110,7 +110,7 @@ void calibrateImage(float **prow, int nrow, int offset, int width, rgparam_t reg for (int y = 0; y < nrow; y++) { for (int x = 0; x < width+SYNC_WIDTH+SPC_WIDTH+TELE_WIDTH; x++) { - float pv = rgcal(prow[y][x + offset], ®r); + float pv = (float)rgcal(prow[y][x + offset], ®r); prow[y][x + offset] = CLIP(pv, 0, 255); } } @@ -126,10 +126,10 @@ double teleNoise(double wedges[16]){ } // Get telemetry data for thermal calibration -int calibrate(float **prow, int nrow, int offset, int width) { - double teleline[MAX_HEIGHT] = { 0.0 }; +int apt_calibrate(float **prow, int nrow, int offset, int width) { + double teleline[APT_MAX_HEIGHT] = { 0.0 }; double wedge[16]; - rgparam_t regr[MAX_HEIGHT/FRAME_LEN + 1]; + rgparam_t regr[APT_MAX_HEIGHT/FRAME_LEN + 1]; int telestart, mtelestart = 0; int channel = -1; @@ -156,8 +156,8 @@ int calibrate(float **prow, int nrow, int offset, int width) { float df; // (sum 4px below) - (sum 4px above) - df = (teleline[n - 4] + teleline[n - 3] + teleline[n - 2] + teleline[n - 1]) - - (teleline[n + 0] + teleline[n + 1] + teleline[n + 2] + teleline[n + 3]); + df = (float)((teleline[n - 4] + teleline[n - 3] + teleline[n - 2] + teleline[n - 1]) - + (teleline[n + 0] + teleline[n + 1] + teleline[n + 2] + teleline[n + 3])); // Find the maximum difference if (df > max) { @@ -197,7 +197,7 @@ int calibrate(float **prow, int nrow, int offset, int width) { // Compute & apply regression on the wedges rgcomp(wedge, ®r[k]); for (int j = 0; j < 16; j++) - tele[j] = rgcal(wedge[j], ®r[k]); + tele[j] = (float)rgcal((float)wedge[j], ®r[k]); /* Compare the channel ID wedge to the reference * wedges, the wedge with the closest match will @@ -205,7 +205,7 @@ int calibrate(float **prow, int nrow, int offset, int width) { */ float min = -1; for (int j = 0; j < 6; j++) { - float df = tele[15] - tele[j]; + float df = (float)(tele[15] - tele[j]); df *= df; if (df < min || min == -1) { @@ -228,7 +228,7 @@ int calibrate(float **prow, int nrow, int offset, int width) { i++; } } - Cs = rgcal(Cs / i, ®r[k]); + Cs = rgcal((float)(Cs / i), ®r[k]); } } @@ -247,7 +247,7 @@ extern float quick_select(float arr[], int n); // Biased median denoise, pretyt ugly #define TRIG_LEVEL 40 -void denoise(float **prow, int nrow, int offset, int width){ +void apt_denoise(float **prow, int nrow, int offset, int width){ for(int y = 2; y < nrow-2; y++){ for(int x = offset+1; x < offset+width-1; x++){ if(prow[y][x+1] - prow[y][x] > TRIG_LEVEL || @@ -267,7 +267,7 @@ void denoise(float **prow, int nrow, int offset, int width){ #undef TRIG_LEVEL // Flips a channel, for northbound passes -void flipImage(image_t *img, int width, int offset){ +void apt_flipImage(apt_image_t *img, int width, int offset){ for(int y = 1; y < img->nrow; y++){ for(int x = 1; x < ceil(width / 2.0); x++){ // Flip top-left & bottom-right @@ -279,11 +279,11 @@ void flipImage(image_t *img, int width, int offset){ } // Calculate crop to reomve noise from the start and end of an image -int cropNoise(image_t *img){ +int apt_cropNoise(apt_image_t *img){ #define NOISE_THRESH 180.0 // Average value of minute marker - float spc_rows[MAX_HEIGHT] = { 0.0 }; + float spc_rows[APT_MAX_HEIGHT] = { 0.0 }; int startCrop = 0; int endCrop = img->nrow; for(int y = 0; y < img->nrow; y++) { for(int x = 0; x < SPC_WIDTH; x++) { @@ -396,7 +396,7 @@ static double tempcal(float Ce, int satnum, tempparam_t * rgpr) { } // Temperature calibration wrapper -void temperature(options_t *opts, image_t *img, int offset, int width){ +void temperature(options_t *opts, apt_image_t *img, int offset, int width){ tempparam_t temp; printf("Temperature... "); @@ -406,7 +406,7 @@ void temperature(options_t *opts, image_t *img, int offset, int width){ for (int y = 0; y < img->nrow; y++) { for (int x = 0; x < width; x++) { - img->prow[y][x + offset] = tempcal(img->prow[y][x + offset], opts->satnum - 15, &temp); + img->prow[y][x + offset] = (float)tempcal(img->prow[y][x + offset], opts->satnum - 15, &temp); } } printf("Done\n"); diff --git a/src/image.h b/src/image.h index 2fb7e8d..ff6309f 100644 --- a/src/image.h +++ b/src/image.h @@ -1,9 +1,4 @@ +#include "apt.h" #include "common.h" -void histogramEqualise(float **prow, int nrow, int offset, int width); -void linearEnhance(float **prow, int nrow, int offset, int width); -int calibrate(float **prow, int nrow, int offset, int width) ; -void denoise(float **prow, int nrow, int offset, int width); -void flipImage(image_t *img, int width, int offset); -int cropNoise(image_t *img); -void temperature(options_t *opts, image_t *img, int offset, int width); +void APT_API temperature(options_t *opts, apt_image_t *img, int offset, int width); diff --git a/src/main.c b/src/main.c index 6c9143d..aa6b424 100644 --- a/src/main.c +++ b/src/main.c @@ -20,7 +20,11 @@ #include #include #include +#ifndef _MSC_VER #include +#else +#include +#endif #include #include #include @@ -28,10 +32,8 @@ #include "libs/argparse.h" #include "offsets.h" - -// DSP -extern int init_dsp(double F); -extern int getpixelrow(float *pixelv, int nrow, int *zenith, int reset); +#include "common.h" +#include "apt.h" #include "pngio.h" #include "image.h" @@ -47,6 +49,23 @@ static int initsnd(char *filename); int getsample(float *sample, int nb); static int processAudio(char *filename, options_t *opts); +#ifdef _MSC_VER +// Functions not supported by MSVC +static char *dirname(char *path) +{ + static char dir[MAX_PATH]; + _splitpath(path, NULL, dir, NULL, NULL); + return dir; +} + +static char *basename(char *path) +{ + static char base[MAX_PATH]; + _splitpath(path, NULL, NULL, base, NULL); + return base; +} +#endif + int main(int argc, const char **argv) { options_t opts = { "r", "", 19, "", ".", 0, "", "", 1.0, 0 }; @@ -98,7 +117,7 @@ int main(int argc, const char **argv) { static int processAudio(char *filename, options_t *opts){ // Image info struct - image_t img; + apt_image_t img; // Mapping between wedge value and channel ID static struct { @@ -125,7 +144,7 @@ static int processAudio(char *filename, options_t *opts){ strncpy(img.name, ctime(&t), 24); // Init a row writer - initWriter(opts, &img, IMG_WIDTH, MAX_HEIGHT, "Unprocessed realtime image", "r"); + initWriter(opts, &img, IMG_WIDTH, APT_MAX_HEIGHT, "Unprocessed realtime image", "r"); } if(strcmp(extension, "png") == 0){ @@ -141,12 +160,12 @@ static int processAudio(char *filename, options_t *opts){ // Build image // TODO: multithreading, would require some sort of input buffer - for (img.nrow = 0; img.nrow < MAX_HEIGHT; img.nrow++) { + for (img.nrow = 0; img.nrow < APT_MAX_HEIGHT; img.nrow++) { // Allocate memory for this row img.prow[img.nrow] = (float *) malloc(sizeof(float) * 2150); // Write into memory and break the loop when there are no more samples to read - if (getpixelrow(img.prow[img.nrow], img.nrow, &img.zenith, (img.nrow == 0)) == 0) + if (apt_getpixelrow(img.prow[img.nrow], img.nrow, &img.zenith, (img.nrow == 0), getsample) == 0) break; if(opts->realtime) pushRow(img.prow[img.nrow], IMG_WIDTH); @@ -171,32 +190,32 @@ static int processAudio(char *filename, options_t *opts){ } // Calibrate - img.chA = calibrate(img.prow, img.nrow, CHA_OFFSET, CH_WIDTH); - img.chB = calibrate(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH); + img.chA = apt_calibrate(img.prow, img.nrow, CHA_OFFSET, CH_WIDTH); + img.chB = apt_calibrate(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH); printf("Channel A: %s (%s)\n", ch.id[img.chA], ch.name[img.chA]); printf("Channel B: %s (%s)\n", ch.id[img.chB], ch.name[img.chB]); // Crop noise from start and end of image if(CONTAINS(opts->effects, Crop_Noise)){ - img.zenith -= cropNoise(&img); + img.zenith -= apt_cropNoise(&img); } // Denoise if(CONTAINS(opts->effects, Denoise)){ - denoise(img.prow, img.nrow, CHA_OFFSET, CH_WIDTH); - denoise(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH); + apt_denoise(img.prow, img.nrow, CHA_OFFSET, CH_WIDTH); + apt_denoise(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH); } // Flip, for northbound passes if(CONTAINS(opts->effects, Flip_Image)){ - flipImage(&img, CH_WIDTH, CHA_OFFSET); - flipImage(&img, CH_WIDTH, CHB_OFFSET); + apt_flipImage(&img, CH_WIDTH, CHA_OFFSET); + apt_flipImage(&img, CH_WIDTH, CHB_OFFSET); } // Temperature if (CONTAINS(opts->type, Temperature) && img.chB >= 4) { // Create another buffer as to not modify the orignal - image_t tmpimg = img; + apt_image_t tmpimg = img; for(int i = 0; i < img.nrow; i++){ tmpimg.prow[i] = (float *) malloc(sizeof(float) * 2150); memcpy(tmpimg.prow[i], img.prow[i], sizeof(float) * 2150); @@ -204,7 +223,7 @@ static int processAudio(char *filename, options_t *opts){ // Perform temperature calibration temperature(opts, &tmpimg, CHB_OFFSET, CH_WIDTH); - ImageOut(opts, &tmpimg, CHB_OFFSET, CH_WIDTH, "Temperature", Temperature, (char *)TempPalette); + ImageOut(opts, &tmpimg, CHB_OFFSET, CH_WIDTH, "Temperature", Temperature, (char *)apt_TempPalette); } // MCIR @@ -213,14 +232,14 @@ static int processAudio(char *filename, options_t *opts){ // Linear equalise if(CONTAINS(opts->effects, Linear_Equalise)){ - linearEnhance(img.prow, img.nrow, CHA_OFFSET, CH_WIDTH); - linearEnhance(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH); + apt_linearEnhance(img.prow, img.nrow, CHA_OFFSET, CH_WIDTH); + apt_linearEnhance(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH); } // Histogram equalise if(CONTAINS(opts->effects, Histogram_Equalise)){ - histogramEqualise(img.prow, img.nrow, CHA_OFFSET, CH_WIDTH); - histogramEqualise(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH); + apt_histogramEqualise(img.prow, img.nrow, CHA_OFFSET, CH_WIDTH); + apt_histogramEqualise(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH); } // Raw image @@ -263,7 +282,7 @@ static int initsnd(char *filename) { return 0; } - res = init_dsp(infwav.samplerate); + res = apt_init(infwav.samplerate); printf("Input file: %s\n", filename); if(res < 0) { fprintf(stderr, "Input sample rate too low: %d\n", infwav.samplerate); @@ -282,14 +301,15 @@ static int initsnd(char *filename) { // Read samples from the audio file int getsample(float *sample, int nb) { if(channels == 1){ - return sf_read_float(audioFile, sample, nb); + return (int)sf_read_float(audioFile, sample, nb); }else{ /* Multi channel audio is encoded such as: * Ch1,Ch2,Ch1,Ch2,Ch1,Ch2 */ - float buf[nb * channels]; // Something like BLKIN*2 could also be used - int samples = sf_read_float(audioFile, buf, nb * channels); + float *buf = malloc(sizeof(float) * nb * channels); // Something like BLKIN*2 could also be used + int samples = (int)sf_read_float(audioFile, buf, nb * channels); for(int i = 0; i < nb; i++) sample[i] = buf[i * channels]; + free(buf); return samples / channels; } } diff --git a/src/pngio.c b/src/pngio.c index a350d19..d0aa95a 100644 --- a/src/pngio.c +++ b/src/pngio.c @@ -26,7 +26,7 @@ #include "pngio.h" -int mapOverlay(char *filename, rgb_t **crow, int nrow, int zenith, int MCIR) { +int mapOverlay(char *filename, apt_rgb_t **crow, int nrow, int zenith, int MCIR) { FILE *fp = fopen(filename, "rb"); if(!fp) { fprintf(stderr, "Cannot open %s\n", filename); @@ -88,7 +88,7 @@ int mapOverlay(char *filename, rgb_t **crow, int nrow, int zenith, int MCIR) { for(int x = 49; x < width - 82; x++){ // Maps are 16 bit / channel png_bytep px = &mapRows[CLIP(y + mapOffset, 0, height-1)][x * 6]; - rgb_t map = { + apt_rgb_t map = { (px[0] << 8) | px[1], (px[2] << 8) | px[3], (px[4] << 8) | px[5] @@ -105,10 +105,10 @@ int mapOverlay(char *filename, rgb_t **crow, int nrow, int zenith, int MCIR) { float darken = ((255-crow[y][chb].r)-100)/50; float green = CLIP(map.g/300, 0, 1); float blue = 0.15 - CLIP(map.b/960.0, 0, 1); - crow[y][cha] = (rgb_t){blue*1000*darken, green*98*darken, blue*500.0*darken}; + crow[y][cha] = (apt_rgb_t){blue*1000*darken, green*98*darken, blue*500.0*darken}; }else{ // Sea - crow[y][cha] = (rgb_t){9, 17, 74}; + crow[y][cha] = (apt_rgb_t){9, 17, 74}; } } @@ -125,15 +125,15 @@ int mapOverlay(char *filename, rgb_t **crow, int nrow, int zenith, int MCIR) { map.b = CLIP(map.b, 0, 255.0); // Map overlay on channel A - crow[y][cha] = RGBcomposite(map, alpha, crow[y][cha], 1); + crow[y][cha] = apt_RGBcomposite(map, alpha, crow[y][cha], 1); // Map overlay on channel B if(!MCIR) - crow[y][chb] = RGBcomposite(map, alpha, crow[y][chb], 1); + crow[y][chb] = apt_RGBcomposite(map, alpha, crow[y][chb], 1); // Cloud overlay on channel A if(MCIR){ float cloud = CLIP((crow[y][chb].r - 113) / 90.0, 0, 1); - crow[y][cha] = RGBcomposite((rgb_t){255, 250, 245}, cloud, crow[y][cha], 1); + crow[y][cha] = apt_RGBcomposite((apt_rgb_t){255, 250, 245}, cloud, crow[y][cha], 1); } } } @@ -206,7 +206,7 @@ int readRawImage(char *filename, float **prow, int *nrow) { return 1; } -int readPalette(char *filename, rgb_t **pixels) { +int readPalette(char *filename, apt_rgb_t **pixels) { FILE *fp = fopen(filename, "rb"); if(!fp) { char buffer[1024]; @@ -266,10 +266,10 @@ int readPalette(char *filename, rgb_t **pixels) { // Put into crow for(int y = 0; y < height; y++) { - pixels[y] = (rgb_t *) malloc(sizeof(rgb_t) * width); + pixels[y] = (apt_rgb_t *) malloc(sizeof(apt_rgb_t) * width); for(int x = 0; x < width; x++) - pixels[y][x] = (rgb_t){ + pixels[y][x] = (apt_rgb_t){ PNGrows[y][x*3], PNGrows[y][x*3 + 1], PNGrows[y][x*3 + 2] @@ -279,21 +279,21 @@ int readPalette(char *filename, rgb_t **pixels) { return 1; } -void prow2crow(float **prow, int nrow, char *palette, rgb_t **crow){ +void prow2crow(float **prow, int nrow, char *palette, apt_rgb_t **crow){ for(int y = 0; y < nrow; y++){ - crow[y] = (rgb_t *) malloc(sizeof(rgb_t) * IMG_WIDTH); + crow[y] = (apt_rgb_t *) malloc(sizeof(apt_rgb_t) * IMG_WIDTH); for(int x = 0; x < IMG_WIDTH; x++){ if(palette == NULL) crow[y][x].r = crow[y][x].g = crow[y][x].b = prow[y][x]; else - crow[y][x] = applyPalette(palette, prow[y][x]); + crow[y][x] = apt_applyPalette(palette, prow[y][x]); } } } -int applyUserPalette(float **prow, int nrow, char *filename, rgb_t **crow){ - rgb_t *pal_row[256]; +int applyUserPalette(float **prow, int nrow, char *filename, apt_rgb_t **crow){ + apt_rgb_t *pal_row[256]; if(!readPalette(filename, pal_row)){ fprintf(stderr, "Could not read palette\n"); return 0; @@ -310,7 +310,7 @@ int applyUserPalette(float **prow, int nrow, char *filename, rgb_t **crow){ return 1; } -int ImageOut(options_t *opts, image_t *img, int offset, int width, char *desc, char chid, char *palette){ +int ImageOut(options_t *opts, apt_image_t *img, int offset, int width, char *desc, char chid, char *palette){ char outName[512]; if(opts->filename == NULL || opts->filename[0] == '\0'){ sprintf(outName, "%s/%s-%c.png", opts->path, img->name, chid); @@ -409,7 +409,7 @@ int ImageOut(options_t *opts, image_t *img, int offset, int width, char *desc, c png_write_info(png_ptr, info_ptr); // Move prow into crow, crow ~ color rows, if required - rgb_t *crow[MAX_HEIGHT]; + apt_rgb_t *crow[APT_MAX_HEIGHT]; if(!greyscale){ prow2crow(img->prow, img->nrow, palette, crow); } @@ -424,7 +424,7 @@ int ImageOut(options_t *opts, image_t *img, int offset, int width, char *desc, c for(int y = 0; y < img->nrow; y++){ for(int x = 0; x < CH_WIDTH; x++){ if(img->prow[y][x + CHB_OFFSET] >= 198) - crow[y][x + CHB_OFFSET] = crow[y][x + CHA_OFFSET] = applyPalette(PrecipPalette, img->prow[y][x + CHB_OFFSET]-198); + crow[y][x + CHB_OFFSET] = crow[y][x + CHA_OFFSET] = apt_applyPalette(apt_PrecipPalette, img->prow[y][x + CHB_OFFSET]-198); } } } @@ -448,8 +448,8 @@ int ImageOut(options_t *opts, image_t *img, int offset, int width, char *desc, c // Build image for (int y = 0; y < img->nrow; y++) { - png_color pix[width]; // Color - png_byte mpix[width]; // Mono + png_color pix[IMG_WIDTH]; // Color + png_byte mpix[IMG_WIDTH]; // Mono int skip = 0; for (int x = 0; x < width; x++) { @@ -488,7 +488,7 @@ png_structp rt_png_ptr; png_infop rt_info_ptr; FILE *rt_pngfile; -int initWriter(options_t *opts, image_t *img, int width, int height, char *desc, char *chid){ +int initWriter(options_t *opts, apt_image_t *img, int width, int height, char *desc, char *chid){ char outName[384]; sprintf(outName, "%s/%s-%s.png", opts->path, img->name, chid); @@ -538,7 +538,7 @@ int initWriter(options_t *opts, image_t *img, int width, int height, char *desc, } void pushRow(float *row, int width){ - png_byte pix[width]; + png_byte pix[IMG_WIDTH]; for(int i = 0; i < width; i++) pix[i] = row[i]; diff --git a/src/pngio.h b/src/pngio.h index cdb7cfd..f52482a 100644 --- a/src/pngio.h +++ b/src/pngio.h @@ -1,13 +1,13 @@ +#include "apt.h" #include "common.h" #include "offsets.h" -#include "color.h" -int mapOverlay(char *filename, rgb_t **crow, int nrow, int zenith, int MCIR); +int mapOverlay(char *filename, apt_rgb_t **crow, int nrow, int zenith, int MCIR); int readRawImage(char *filename, float **prow, int *nrow); -int readPalette(char *filename, rgb_t **pixels); -void prow2crow(float **prow, int nrow, char *palette, rgb_t **crow); -int applyUserPalette(float **prow, int nrow, char *filename, rgb_t **crow); -int ImageOut(options_t *opts, image_t *img, int offset, int width, char *desc, char chid, char *palette); -int initWriter(options_t *opts, image_t *img, int width, int height, char *desc, char *chid); +int readPalette(char *filename, apt_rgb_t **pixels); +void prow2crow(float **prow, int nrow, char *palette, apt_rgb_t **crow); +int applyUserPalette(float **prow, int nrow, char *filename, apt_rgb_t **crow); +int ImageOut(options_t *opts, apt_image_t *img, int offset, int width, char *desc, char chid, char *palette); +int initWriter(options_t *opts, apt_image_t *img, int width, int height, char *desc, char *chid); void pushRow(float *row, int width); void closeWriter(); diff --git a/src/satcal.h b/src/satcal.h index 2615ce1..a68a95e 100644 --- a/src/satcal.h +++ b/src/satcal.h @@ -32,94 +32,94 @@ const struct { } satcal[] = { { // NOAA 15 { // PRT coefficient d0, d1, d2 - {276.60157, 0.051045, 1.36328E-06}, - {276.62531, 0.050909, 1.47266E-06}, - {276.67413, 0.050907, 1.47656E-06}, - {276.59258, 0.050966, 1.47656E-06} + {276.60157f, 0.051045f, 1.36328E-06f}, + {276.62531f, 0.050909f, 1.47266E-06f}, + {276.67413f, 0.050907f, 1.47656E-06f}, + {276.59258f, 0.050966f, 1.47656E-06f} }, { // Channel radiance coefficient vc, A, B - {925.4075, 0.337810, 0.998719}, // Channel 4 - {839.8979, 0.304558, 0.999024}, // Channel 5 - {2695.9743, 1.621256, 0.998015} // Channel 3B + {925.4075f, 0.337810f, 0.998719f}, // Channel 4 + {839.8979f, 0.304558f, 0.999024f}, // Channel 5 + {2695.9743f, 1.621256f, 0.998015f} // Channel 3B }, { // Nonlinear radiance correction Ns, b0, b1, b2 - {-4.50, {4.76, -0.0932, 0.0004524}}, // Channel 4 - {-3.61, {3.83, -0.0659, 0.0002811}}, // Channel 5 - {0.0, {0.0, 0.0, 0.0}} // Channel 3B + {-4.50f, {4.76f, -0.0932f, 0.0004524f}}, // Channel 4 + {-3.61f, {3.83f, -0.0659f, 0.0002811f}}, // Channel 5 + {0.0f, {0.0f, 0.0f, 0.0f}} // Channel 3B } }, { // NOAA 16 { // PRT coeff d0, d1, d2 - {276.355, 5.562E-02, -1.590E-05}, - {276.142, 5.605E-02, -1.707E-05}, - {275.996, 5.486E-02, -1.223E-05}, - {276.132, 5.494E-02, -1.344E-05} + {276.355f, 5.562E-02f, -1.590E-05f}, + {276.142f, 5.605E-02f, -1.707E-05f}, + {275.996f, 5.486E-02f, -1.223E-05f}, + {276.132f, 5.494E-02f, -1.344E-05f} }, { // Channel radiance coefficient vc, A, B - {917.2289, 0.332380, 0.998522}, // Channel 4 - {838.1255, 0.674623, 0.998363}, // Channel 5 - {2700.1148, 1.592459, 0.998147} // Channel 3B + {917.2289f, 0.332380f, 0.998522f}, // Channel 4 + {838.1255f, 0.674623f, 0.998363f}, // Channel 5 + {2700.1148f, 1.592459f, 0.998147f} // Channel 3B }, { // Nonlinear radiance correction Ns, b0, b1, b2 - {-2.467, {2.96, -0.05411, 0.00024532}}, // Channel 4 - {-2.009, {2.25, -0.03665, 0.00014854}}, // Channel 5 - {0.0, {0.0, 0.0, 0.0}} // Channel 3B + {-2.467f, {2.96f, -0.05411f, 0.00024532f}}, // Channel 4 + {-2.009f, {2.25f, -0.03665f, 0.00014854f}}, // Channel 5 + {0.0f, {0.0f, 0.0f, 0.0f}} // Channel 3B } }, { // NOAA 17 { // PRT coefficient d0, d1, d2 - {276.628, 0.05098, 1.371e-06}, - {276.538, 0.05098, 1.371e-06}, - {276.761, 0.05097, 1.369e-06}, - {276.660, 0.05100, 1.348e-06} + {276.628f, 0.05098f, 1.371e-06f}, + {276.538f, 0.05098f, 1.371e-06f}, + {276.761f, 0.05097f, 1.369e-06f}, + {276.660f, 0.05100f, 1.348e-06f} }, { // Channel radiance coefficient vc, A, B - {926.2947, 0.271683, 0.998794}, // Channel 4 - {839.8246, 0.309180, 0.999012}, // Channel 5 - {2669.3554, 1.702380, 0.997378} // Channel 3B + {926.2947f, 0.271683f, 0.998794f}, // Channel 4 + {839.8246f, 0.309180f, 0.999012f}, // Channel 5 + {2669.3554f, 1.702380f, 0.997378f} // Channel 3B }, { // Nonlinear radiance correction Ns, b0, b1, b2 - {-8.55, {8.22, -0.15795, 0.00075579}}, // Channel 4 - {-3.97, {4.31, -0.07318, 0.00030976}}, // Channel 5 - {0.0, {0.0, 0.0, 0.0}} // Channel 3B + {-8.55f, {8.22f, -0.15795f, 0.00075579f}}, // Channel 4 + {-3.97f, {4.31f, -0.07318f, 0.00030976f}}, // Channel 5 + {0.0f, {0.0f, 0.0f, 0.0f}} // Channel 3B } }, { // NOAA 18 { // PRT coefficient d0, d1, d2 - {276.601, 0.05090, 1.657e-06}, - {276.683, 0.05101, 1.482e-06}, - {276.565, 0.05117, 1.313e-06}, - {276.615, 0.05103, 1.484e-06} + {276.601f, 0.05090f, 1.657e-06f}, + {276.683f, 0.05101f, 1.482e-06f}, + {276.565f, 0.05117f, 1.313e-06f}, + {276.615f, 0.05103f, 1.484e-06f} }, { // Channel radiance coefficient vc, A, B - {928.1460, 0.436645, 0.998607}, // Channel 4 - {833.2532, 0.253179, 0.999057}, // Channel 5 - {2659.7952, 1.698704, 0.996960} // Channel 3B + {928.1460f, 0.436645f, 0.998607f}, // Channel 4 + {833.2532f, 0.253179f, 0.999057f}, // Channel 5 + {2659.7952f, 1.698704f, 0.996960f} // Channel 3B }, { // Nonlinear radiance correction Ns, b0, b1, b2 - {-5.53, {5.82, -0.11069, 0.00052337}}, // Channel 4 - {-2.22, {2.67, -0.04360, 0.00017715}}, // Channel 5 - {0.0, {0.0, 0.0, 0.0}} // Channel 3B + {-5.53f, {5.82f, -0.11069f, 0.00052337f}}, // Channel 4 + {-2.22f, {2.67f, -0.04360f, 0.00017715f}}, // Channel 5 + {0.0f, {0.0f, 0.0f, 0.0f}} // Channel 3B } }, { // NOAA 19 { // PRT coefficient d0, d1, d2 - {276.6067, 0.051111, 1.405783E-06}, - {276.6119, 0.051090, 1.496037E-06}, - {276.6311, 0.051033, 1.496990E-06}, - {276.6268, 0.051058, 1.493110E-06} + {276.6067f, 0.051111f, 1.405783E-06f}, + {276.6119f, 0.051090f, 1.496037E-06f}, + {276.6311f, 0.051033f, 1.496990E-06f}, + {276.6268f, 0.051058f, 1.493110E-06f} }, { // Channel radiance coefficient vc, A, B - {928.9, 0.53959, 0.998534}, // Channel 4 - {831.9, 0.36064, 0.998913}, // Channel 5 - {2670.0, 1.67396, 0.997364} // Channel 3B + {928.9f, 0.53959f, 0.998534f}, // Channel 4 + {831.9f, 0.36064f, 0.998913f}, // Channel 5 + {2670.0f, 1.67396f, 0.997364f} // Channel 3B }, { // Nonlinear radiance correction Ns, b0, b1, b2 - {-5.49, {5.70 -0.11187, 0.00054668}}, // Channel 4 - {-3.39, {3.58 -0.05991, 0.00024985}}, // Channel 5 - {0.0, {0.0, 0.0, 0.0}} // Channel 3B + {-5.49f, {5.70f, -0.11187f, 0.00054668f}}, // Channel 4 + {-3.39f, {3.58f, -0.05991f, 0.00024985f}}, // Channel 5 + {0.0f, {0.0f, 0.0f, 0.0f}} // Channel 3B } }}; -const float c1 = 1.1910427e-5; -const float c2 = 1.4387752; +const float c1 = 1.1910427e-5f; +const float c2 = 1.4387752f; From 429e73a2b1f258450d3c5b07184e9cdcba5780a1 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Tue, 16 Feb 2021 17:09:39 +0000 Subject: [PATCH 02/14] Fix palette exports --- src/apt.h | 4 ++-- src/color.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/apt.h b/src/apt.h index f5e03ca..d0894ba 100644 --- a/src/apt.h +++ b/src/apt.h @@ -61,7 +61,7 @@ int APT_API apt_cropNoise(apt_image_t *img); apt_rgb_t APT_API apt_applyPalette(char *palette, int val); apt_rgb_t APT_API apt_RGBcomposite(apt_rgb_t top, float top_a, apt_rgb_t bottom, float bottom_a); -char APT_API apt_TempPalette[256*3]; -char APT_API apt_PrecipPalette[58*3]; +extern char APT_API apt_TempPalette[256*3]; +extern char APT_API apt_PrecipPalette[58*3]; #endif diff --git a/src/color.c b/src/color.c index c49bade..9d1b635 100644 --- a/src/color.c +++ b/src/color.c @@ -37,7 +37,7 @@ apt_rgb_t apt_RGBcomposite(apt_rgb_t top, float top_a, apt_rgb_t bottom, float b } // The "I totally didn't just steal this from WXtoImg" palette -char TempPalette[256*3] = { +char apt_TempPalette[256*3] = { "\x45\x0\x8f\x46\x0\x91\x47\x0\x92\x48\x0\x94\x49\x0\x96\x4a\x0\x98\x4b\x0\x9b\x4d\x0\x9d" "\x4e\x0\xa0\x50\x0\xa2\x51\x0\xa5\x52\x0\xa7\x54\x0\xaa\x56\x0\xae\x57\x0\xb1" "\x58\x0\xb4\x5a\x0\xb7\x5c\x0\xba\x5e\x0\xbd\x5f\x0\xc0\x61\x0\xc4\x64\x0\xc8" @@ -77,7 +77,7 @@ char TempPalette[256*3] = { "\xc8\x0\x0\xcc\x0\x0\xcc\x0\x0" }; -char PrecipPalette[58*3] = { +char apt_PrecipPalette[58*3] = { "\x8\x89\x41\x0\xc5\x44\x0\xd1\x2c\x0\xe3\x1c\x0\xf9\x6\x14\xff\x0\x3e\xff\x0\x5d\xff\x0" "\x80\xff\x0\xab\xff\x0\xcd\xfe\x0\xf8\xff\x0\xff\xe6\x0\xff\xb8\x0\xff\x98\x0" "\xff\x75\x0\xff\x49\x0\xfe\x26\x0\xff\x4\x0\xdf\x0\x0\xa8\x0\x0\x87\x0\x0" From 4aca94f20f14a79b7b000637a2d395ae16a4450a Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Tue, 16 Feb 2021 17:10:19 +0000 Subject: [PATCH 03/14] Use INCLUDE_DIRs for libraries. Simplify conditions --- CMakeLists.txt | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 53b01b7..713db96 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,10 +19,14 @@ add_compile_definitions(PALETTE_DIR="../palettes") if (PNG_FOUND AND LIBSNDFILE_FOUND) add_executable(aptdec ${EXE_C_SOURCE_FILES}) - target_link_libraries(aptdec PRIVATE libaptdec) + include_directories(${PNG_PNG_INCLUDE_DIR}) + include_directories(${LIBSNDFILE_INCLUDE_DIR}) target_link_libraries(aptdec PRIVATE PNG::PNG) target_link_libraries(aptdec PRIVATE ${LIBSNDFILE_LIBRARY}) - if (CLANG OR GCC) + target_link_libraries(aptdec PRIVATE libaptdec) + if (MSVC) + target_compile_options(aptdec PRIVATE /D_CRT_SECURE_NO_WARNINGS=1) + else() # Math target_link_libraries(aptdec PRIVATE m) @@ -32,21 +36,22 @@ if (PNG_FOUND AND LIBSNDFILE_FOUND) else() target_compile_options(aptdec PRIVATE -Wall -Wextra -pedantic) endif() - elseif (MSVC) - target_compile_options(aptdec PRIVATE /D_CRT_SECURE_NO_WARNINGS=1) endif() else() MESSAGE(STATUS "WARNING: Only building libaptdec, as not all of the required libraries were found.") endif() -if (CLANG OR CGCC) +if (MSVC) + target_compile_options(libaptdec PRIVATE /D_CRT_SECURE_NO_WARNINGS=1) +else() + # Math + target_link_libraries(libaptdec PRIVATE m) + if(CMAKE_BUILD_TYPE MATCHES "Release") target_compile_options(libaptdec PRIVATE -Wall -Wextra -pedantic -Wno-missing-field-initializers -Werror) else() target_compile_options(libaptdec PRIVATE -Wall -Wextra -pedantic) endif() -elseif (MSVC) - target_compile_options(libaptdec PRIVATE /D_CRT_SECURE_NO_WARNINGS=1) endif() # TODO: get this from git From fb6fb499293fe53db4b8bc80fe892ad8a00bc4f9 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Tue, 16 Feb 2021 19:45:04 +0000 Subject: [PATCH 04/14] Use static library for aptdec executable, to avoid having to set path to library --- CMakeLists.txt | 10 +++++++--- src/apt.h | 6 ++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 713db96..6a3ca83 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,9 @@ set(LIB_C_SOURCE_FILES src/color.c src/dsp.c src/filter.c src/image.c src/libs/r set(EXE_C_SOURCE_FILES src/main.c src/pngio.c src/libs/argparse.c) set(LIB_C_HEADER_FILES src/apt.h) +# Link with static library for aptdec executable, so we don't need to set the path +add_library(libaptdecstatic STATIC ${LIB_C_SOURCE_FILES}) +# Create shared library for 3rd party apps add_library(libaptdec SHARED ${LIB_C_SOURCE_FILES}) add_compile_definitions(PALETTE_DIR="../palettes") @@ -23,9 +26,9 @@ if (PNG_FOUND AND LIBSNDFILE_FOUND) include_directories(${LIBSNDFILE_INCLUDE_DIR}) target_link_libraries(aptdec PRIVATE PNG::PNG) target_link_libraries(aptdec PRIVATE ${LIBSNDFILE_LIBRARY}) - target_link_libraries(aptdec PRIVATE libaptdec) + target_link_libraries(aptdec PRIVATE libaptdecstatic) if (MSVC) - target_compile_options(aptdec PRIVATE /D_CRT_SECURE_NO_WARNINGS=1) + target_compile_options(aptdec PRIVATE /D_CRT_SECURE_NO_WARNINGS=1 /DAPT_API_STATIC) else() # Math target_link_libraries(aptdec PRIVATE m) @@ -42,10 +45,11 @@ else() endif() if (MSVC) - target_compile_options(libaptdec PRIVATE /D_CRT_SECURE_NO_WARNINGS=1) + target_compile_options(libaptdec PRIVATE /D_CRT_SECURE_NO_WARNINGS=1 /DAPT_API_EXPORT) else() # Math target_link_libraries(libaptdec PRIVATE m) + target_link_libraries(libaptdecstatic PRIVATE m) if(CMAKE_BUILD_TYPE MATCHES "Release") target_compile_options(libaptdec PRIVATE -Wall -Wextra -pedantic -Wno-missing-field-initializers -Werror) diff --git a/src/apt.h b/src/apt.h index d0894ba..512b3c0 100644 --- a/src/apt.h +++ b/src/apt.h @@ -24,7 +24,13 @@ #if defined (__GNUC__) && (__GNUC__ >= 4) #define APT_API __attribute__((visibility("default"))) #elif defined (_MSC_VER) +#ifdef APT_API_EXPORT #define APT_API __declspec(dllexport) +#elif APT_API_STATIC +#define APT_API +#else if +#define APT_API __declspec(dllimport) +#endif #else #define APT_API #endif From 42b6e36e4757a428b452d8ef8cb17b1c33e9d423 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Tue, 16 Feb 2021 19:48:43 +0000 Subject: [PATCH 05/14] Fix .bat file comments --- build_windows.bat | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build_windows.bat b/build_windows.bat index 94b9662..c329185 100644 --- a/build_windows.bat +++ b/build_windows.bat @@ -1,7 +1,7 @@ -# Build using Visual Studio 2019 on Windows -# Additional tools needed: git, cmake and ninja +REM Build using Visual Studio 2019 on Windows +REM Additional tools needed: git, cmake and ninja -# Build zlib +REM Build zlib git clone https://github.com/madler/zlib cd zlib mkdir build @@ -10,7 +10,7 @@ cmake -G Ninja -DCMAKE_C_COMPILER="cl.exe" -DMSVC_TOOLSET_VERSION=190 -DCMAKE_BU ninja install cd ../../ -# Build libpng +REM Build libpng git clone https://github.com/glennrp/libpng cd libpng mkdir build @@ -19,7 +19,7 @@ cmake -G Ninja -DCMAKE_C_COMPILER="cl.exe" -DMSVC_TOOLSET_VERSION=190 -DCMAKE_BU ninja install cd ../.. -# Build libsndfile - Could build Vorbis, FLAC and Opus first for extra support +REM Build libsndfile - Could build Vorbis, FLAC and Opus first for extra support git clone https://github.com/libsndfile/libsndfile.git cd libsndfile mkdir build @@ -28,7 +28,7 @@ cmake -G Ninja -DCMAKE_C_COMPILER="cl.exe" -DMSVC_TOOLSET_VERSION=190 -DCMAKE_BU ninja install cd ../.. -# 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 .. From 8cdb314c0f4dcc93ac1481ce3efee97132f00c70 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Tue, 16 Feb 2021 19:54:49 +0000 Subject: [PATCH 06/14] Return to src root --- build_windows.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_windows.bat b/build_windows.bat index c329185..c0872ec 100644 --- a/build_windows.bat +++ b/build_windows.bat @@ -33,4 +33,4 @@ 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 ../.. +cd .. From 17950dc47eebcc2537e4deae59d0c940c07e645d Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Tue, 16 Feb 2021 20:08:14 +0000 Subject: [PATCH 07/14] Rename library so lib isn't repeated on Linux --- CMakeLists.txt | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a3ca83..b7173c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,9 +14,9 @@ set(EXE_C_SOURCE_FILES src/main.c src/pngio.c src/libs/argparse.c) set(LIB_C_HEADER_FILES src/apt.h) # Link with static library for aptdec executable, so we don't need to set the path -add_library(libaptdecstatic STATIC ${LIB_C_SOURCE_FILES}) +add_library(aptstatic STATIC ${LIB_C_SOURCE_FILES}) # Create shared library for 3rd party apps -add_library(libaptdec SHARED ${LIB_C_SOURCE_FILES}) +add_library(apt SHARED ${LIB_C_SOURCE_FILES}) add_compile_definitions(PALETTE_DIR="../palettes") @@ -26,7 +26,7 @@ if (PNG_FOUND AND LIBSNDFILE_FOUND) include_directories(${LIBSNDFILE_INCLUDE_DIR}) target_link_libraries(aptdec PRIVATE PNG::PNG) target_link_libraries(aptdec PRIVATE ${LIBSNDFILE_LIBRARY}) - target_link_libraries(aptdec PRIVATE libaptdecstatic) + target_link_libraries(aptdec PRIVATE aptstatic) if (MSVC) target_compile_options(aptdec PRIVATE /D_CRT_SECURE_NO_WARNINGS=1 /DAPT_API_STATIC) else() @@ -41,20 +41,21 @@ if (PNG_FOUND AND LIBSNDFILE_FOUND) endif() endif() else() - MESSAGE(STATUS "WARNING: Only building libaptdec, as not all of the required libraries were found.") + MESSAGE(STATUS "WARNING: Only building apt library, as not all of the required libraries were found for aptdec.") endif() if (MSVC) - target_compile_options(libaptdec PRIVATE /D_CRT_SECURE_NO_WARNINGS=1 /DAPT_API_EXPORT) + target_compile_options(apt PRIVATE /D_CRT_SECURE_NO_WARNINGS=1 /DAPT_API_EXPORT) + target_compile_options(aptstatic PRIVATE /D_CRT_SECURE_NO_WARNINGS=1 /DAPT_API_STATIC) else() # Math - target_link_libraries(libaptdec PRIVATE m) - target_link_libraries(libaptdecstatic PRIVATE m) + target_link_libraries(apt PRIVATE m) + target_link_libraries(aptstatic PRIVATE m) if(CMAKE_BUILD_TYPE MATCHES "Release") - target_compile_options(libaptdec PRIVATE -Wall -Wextra -pedantic -Wno-missing-field-initializers -Werror) + target_compile_options(apt PRIVATE -Wall -Wextra -pedantic -Wno-missing-field-initializers -Werror) else() - target_compile_options(libaptdec PRIVATE -Wall -Wextra -pedantic) + target_compile_options(apt PRIVATE -Wall -Wextra -pedantic) endif() endif() @@ -79,7 +80,7 @@ IF(NOT WIN32) install(DIRECTORY "${PROJECT_SOURCE_DIR}/palettes/" DESTINATION "palettes/") endif() - install(TARGETS libaptdec LIBRARY DESTINATION lib) + install(TARGETS apt LIBRARY DESTINATION lib) install(FILES ${LIB_C_HEADER_FILES} DESTINATION include/apt ) else() #set(CPACK_GENERATOR "ZIP;NSIS") @@ -91,7 +92,7 @@ else() file(GLOB_RECURSE DLLS *.dll) install(FILES ${DLLS} DESTINATION "bin/") endif() - install(TARGETS libaptdec DESTINATION "bin/") + install(TARGETS apt DESTINATION "bin/") install(FILES ${LIB_C_HEADER_FILES} DESTINATION include/apt ) install(DIRECTORY "${PROJECT_SOURCE_DIR}/palettes/" DESTINATION "palettes/") endif() From ce63316fb2fc217989a92d41ec3e1a6a1b900324 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Tue, 16 Feb 2021 20:43:14 +0000 Subject: [PATCH 08/14] Support C++ --- src/apt.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/apt.h b/src/apt.h index 512b3c0..4a44037 100644 --- a/src/apt.h +++ b/src/apt.h @@ -21,6 +21,10 @@ #ifndef APT_H #define APT_H +#ifdef __cplusplus +extern "C" { +#endif + #if defined (__GNUC__) && (__GNUC__ >= 4) #define APT_API __attribute__((visibility("default"))) #elif defined (_MSC_VER) @@ -70,4 +74,8 @@ apt_rgb_t APT_API apt_RGBcomposite(apt_rgb_t top, float top_a, apt_rgb_t bottom, extern char APT_API apt_TempPalette[256*3]; extern char APT_API apt_PrecipPalette[58*3]; +#ifdef __cplusplus +} +#endif + #endif From 23d7870102b2bad597ae7717821b8da805f0cddb Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Tue, 16 Feb 2021 20:52:39 +0000 Subject: [PATCH 09/14] Add context pointer to getsample callback --- src/apt.h | 7 ++++--- src/dsp.c | 16 ++++++++-------- src/main.c | 6 +++--- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/apt.h b/src/apt.h index 4a44037..b97d745 100644 --- a/src/apt.h +++ b/src/apt.h @@ -42,8 +42,9 @@ extern "C" { // Maximum height of an APT image in number of scanlines #define APT_MAX_HEIGHT 3000 -// apt_getpixelrow callback function to get audio samples -typedef int (*apt_getsample_t)(float *samples, int count); +// apt_getpixelrow callback function to get audio samples. +// context is the same as passed to apt_getpixelrow. +typedef int (*apt_getsample_t)(void *context, float *samples, int count); typedef struct { float *prow[APT_MAX_HEIGHT]; // Row buffers @@ -59,7 +60,7 @@ typedef struct { } apt_rgb_t; int APT_API apt_init(double sample_rate); -int APT_API apt_getpixelrow(float *pixelv, int nrow, int *zenith, int reset, apt_getsample_t getsample); +int APT_API apt_getpixelrow(float *pixelv, int nrow, int *zenith, int reset, apt_getsample_t getsample, void *context); void APT_API apt_histogramEqualise(float **prow, int nrow, int offset, int width); void APT_API apt_linearEnhance(float **prow, int nrow, int offset, int width); diff --git a/src/dsp.c b/src/dsp.c index 188f44c..e9becd7 100755 --- a/src/dsp.c +++ b/src/dsp.c @@ -131,7 +131,7 @@ static double pll(double I, double Q) { } // Convert samples into pixels -static int getamp(double *ampbuff, int count, apt_getsample_t getsample) { +static int getamp(double *ampbuff, int count, apt_getsample_t getsample, void *context) { static float inbuff[BLKIN]; static int idxin = 0; static int nin = 0; @@ -147,7 +147,7 @@ static int getamp(double *ampbuff, int count, apt_getsample_t getsample) { idxin = 0; // Read some samples - res = getsample(&(inbuff[nin]), BLKIN - nin); + res = getsample(context, &(inbuff[nin]), BLKIN - nin); nin += res; // Make sure there is enough samples to continue @@ -168,7 +168,7 @@ static int getamp(double *ampbuff, int count, apt_getsample_t getsample) { } // Sub-pixel offsetting + FIR compensation -int getpixelv(float *pvbuff, int count, apt_getsample_t getsample) { +int getpixelv(float *pvbuff, int count, apt_getsample_t getsample, void *context) { // Amplitude buffer static double ampbuff[BLKAMP]; static int nam = 0; @@ -187,7 +187,7 @@ int getpixelv(float *pvbuff, int count, apt_getsample_t getsample) { int res; memmove(ampbuff, &(ampbuff[idxam]), nam * sizeof(double)); idxam = 0; - res = getamp(&(ampbuff[nam]), BLKAMP - nam, getsample); + res = getamp(&(ampbuff[nam]), BLKAMP - nam, getsample, context); nam += res; if (nam < m) return n; @@ -207,7 +207,7 @@ int getpixelv(float *pvbuff, int count, apt_getsample_t getsample) { } // Get an entire row of pixels, aligned with sync markers -int apt_getpixelrow(float *pixelv, int nrow, int *zenith, int reset, apt_getsample_t getsample) { +int apt_getpixelrow(float *pixelv, int nrow, int *zenith, int reset, apt_getsample_t getsample, void *context) { static float pixels[PixelLine + SyncFilterLen]; static int npv; static int synced = 0; @@ -225,7 +225,7 @@ int apt_getpixelrow(float *pixelv, int nrow, int *zenith, int reset, apt_getsamp // Get the sync line if (npv < SyncFilterLen + 2) { - res = getpixelv(&(pixelv[npv]), SyncFilterLen + 2 - npv, getsample); + res = getpixelv(&(pixelv[npv]), SyncFilterLen + 2 - npv, getsample, context); npv += res; if (npv < SyncFilterLen + 2) return 0; @@ -256,7 +256,7 @@ int apt_getpixelrow(float *pixelv, int nrow, int *zenith, int reset, apt_getsamp static int lastmshift; if (npv < PixelLine + SyncFilterLen) { - res = getpixelv(&(pixelv[npv]), PixelLine + SyncFilterLen - npv, getsample); + res = getpixelv(&(pixelv[npv]), PixelLine + SyncFilterLen - npv, getsample, context); npv += res; if (npv < PixelLine + SyncFilterLen) return 0; @@ -294,7 +294,7 @@ int apt_getpixelrow(float *pixelv, int nrow, int *zenith, int reset, apt_getsamp // Get the rest of this row if (npv < PixelLine) { - res = getpixelv(&(pixelv[npv]), PixelLine - npv, getsample); + res = getpixelv(&(pixelv[npv]), PixelLine - npv, getsample, context); npv += res; if (npv < PixelLine) return 0; diff --git a/src/main.c b/src/main.c index aa6b424..46e5bdc 100644 --- a/src/main.c +++ b/src/main.c @@ -46,7 +46,7 @@ int channels = 1; // Function declarations static int initsnd(char *filename); -int getsample(float *sample, int nb); +int getsample(void *context, float *sample, int nb); static int processAudio(char *filename, options_t *opts); #ifdef _MSC_VER @@ -165,7 +165,7 @@ static int processAudio(char *filename, options_t *opts){ img.prow[img.nrow] = (float *) malloc(sizeof(float) * 2150); // Write into memory and break the loop when there are no more samples to read - if (apt_getpixelrow(img.prow[img.nrow], img.nrow, &img.zenith, (img.nrow == 0), getsample) == 0) + if (apt_getpixelrow(img.prow[img.nrow], img.nrow, &img.zenith, (img.nrow == 0), getsample, NULL) == 0) break; if(opts->realtime) pushRow(img.prow[img.nrow], IMG_WIDTH); @@ -299,7 +299,7 @@ static int initsnd(char *filename) { } // Read samples from the audio file -int getsample(float *sample, int nb) { +int getsample(void *context, float *sample, int nb) { if(channels == 1){ return (int)sf_read_float(audioFile, sample, nb); }else{ From 3141493ae68f4f377e1bafaa4848d3cfb9a4fb09 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Tue, 16 Feb 2021 21:03:47 +0000 Subject: [PATCH 10/14] Rename apt_getsample to apt_getsamples, as it gets more than one sample. --- src/apt.h | 4 ++-- src/dsp.c | 16 ++++++++-------- src/main.c | 14 +++++++------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/apt.h b/src/apt.h index b97d745..022f00a 100644 --- a/src/apt.h +++ b/src/apt.h @@ -44,7 +44,7 @@ extern "C" { // apt_getpixelrow callback function to get audio samples. // context is the same as passed to apt_getpixelrow. -typedef int (*apt_getsample_t)(void *context, float *samples, int count); +typedef int (*apt_getsamples_t)(void *context, float *samples, int count); typedef struct { float *prow[APT_MAX_HEIGHT]; // Row buffers @@ -60,7 +60,7 @@ typedef struct { } apt_rgb_t; int APT_API apt_init(double sample_rate); -int APT_API apt_getpixelrow(float *pixelv, int nrow, int *zenith, int reset, apt_getsample_t getsample, void *context); +int APT_API apt_getpixelrow(float *pixelv, int nrow, int *zenith, int reset, apt_getsamples_t getsamples, void *context); void APT_API apt_histogramEqualise(float **prow, int nrow, int offset, int width); void APT_API apt_linearEnhance(float **prow, int nrow, int offset, int width); diff --git a/src/dsp.c b/src/dsp.c index e9becd7..63bf1da 100755 --- a/src/dsp.c +++ b/src/dsp.c @@ -131,7 +131,7 @@ static double pll(double I, double Q) { } // Convert samples into pixels -static int getamp(double *ampbuff, int count, apt_getsample_t getsample, void *context) { +static int getamp(double *ampbuff, int count, apt_getsamples_t getsamples, void *context) { static float inbuff[BLKIN]; static int idxin = 0; static int nin = 0; @@ -147,7 +147,7 @@ static int getamp(double *ampbuff, int count, apt_getsample_t getsample, void *c idxin = 0; // Read some samples - res = getsample(context, &(inbuff[nin]), BLKIN - nin); + res = getsamples(context, &(inbuff[nin]), BLKIN - nin); nin += res; // Make sure there is enough samples to continue @@ -168,7 +168,7 @@ static int getamp(double *ampbuff, int count, apt_getsample_t getsample, void *c } // Sub-pixel offsetting + FIR compensation -int getpixelv(float *pvbuff, int count, apt_getsample_t getsample, void *context) { +int getpixelv(float *pvbuff, int count, apt_getsamples_t getsamples, void *context) { // Amplitude buffer static double ampbuff[BLKAMP]; static int nam = 0; @@ -187,7 +187,7 @@ int getpixelv(float *pvbuff, int count, apt_getsample_t getsample, void *context int res; memmove(ampbuff, &(ampbuff[idxam]), nam * sizeof(double)); idxam = 0; - res = getamp(&(ampbuff[nam]), BLKAMP - nam, getsample, context); + res = getamp(&(ampbuff[nam]), BLKAMP - nam, getsamples, context); nam += res; if (nam < m) return n; @@ -207,7 +207,7 @@ int getpixelv(float *pvbuff, int count, apt_getsample_t getsample, void *context } // Get an entire row of pixels, aligned with sync markers -int apt_getpixelrow(float *pixelv, int nrow, int *zenith, int reset, apt_getsample_t getsample, void *context) { +int apt_getpixelrow(float *pixelv, int nrow, int *zenith, int reset, apt_getsamples_t getsamples, void *context) { static float pixels[PixelLine + SyncFilterLen]; static int npv; static int synced = 0; @@ -225,7 +225,7 @@ int apt_getpixelrow(float *pixelv, int nrow, int *zenith, int reset, apt_getsamp // Get the sync line if (npv < SyncFilterLen + 2) { - res = getpixelv(&(pixelv[npv]), SyncFilterLen + 2 - npv, getsample, context); + res = getpixelv(&(pixelv[npv]), SyncFilterLen + 2 - npv, getsamples, context); npv += res; if (npv < SyncFilterLen + 2) return 0; @@ -256,7 +256,7 @@ int apt_getpixelrow(float *pixelv, int nrow, int *zenith, int reset, apt_getsamp static int lastmshift; if (npv < PixelLine + SyncFilterLen) { - res = getpixelv(&(pixelv[npv]), PixelLine + SyncFilterLen - npv, getsample, context); + res = getpixelv(&(pixelv[npv]), PixelLine + SyncFilterLen - npv, getsamples, context); npv += res; if (npv < PixelLine + SyncFilterLen) return 0; @@ -294,7 +294,7 @@ int apt_getpixelrow(float *pixelv, int nrow, int *zenith, int reset, apt_getsamp // Get the rest of this row if (npv < PixelLine) { - res = getpixelv(&(pixelv[npv]), PixelLine - npv, getsample, context); + res = getpixelv(&(pixelv[npv]), PixelLine - npv, getsamples, context); npv += res; if (npv < PixelLine) return 0; diff --git a/src/main.c b/src/main.c index 46e5bdc..3b9ea07 100644 --- a/src/main.c +++ b/src/main.c @@ -46,7 +46,7 @@ int channels = 1; // Function declarations static int initsnd(char *filename); -int getsample(void *context, float *sample, int nb); +int getsamples(void *context, float *samples, int nb); static int processAudio(char *filename, options_t *opts); #ifdef _MSC_VER @@ -165,7 +165,7 @@ static int processAudio(char *filename, options_t *opts){ img.prow[img.nrow] = (float *) malloc(sizeof(float) * 2150); // Write into memory and break the loop when there are no more samples to read - if (apt_getpixelrow(img.prow[img.nrow], img.nrow, &img.zenith, (img.nrow == 0), getsample, NULL) == 0) + if (apt_getpixelrow(img.prow[img.nrow], img.nrow, &img.zenith, (img.nrow == 0), getsamples, NULL) == 0) break; if(opts->realtime) pushRow(img.prow[img.nrow], IMG_WIDTH); @@ -299,17 +299,17 @@ static int initsnd(char *filename) { } // Read samples from the audio file -int getsample(void *context, float *sample, int nb) { +int getsamples(void *context, float *samples, int nb) { if(channels == 1){ - return (int)sf_read_float(audioFile, sample, nb); + return (int)sf_read_float(audioFile, samples, nb); }else{ /* Multi channel audio is encoded such as: * Ch1,Ch2,Ch1,Ch2,Ch1,Ch2 */ float *buf = malloc(sizeof(float) * nb * channels); // Something like BLKIN*2 could also be used - int samples = (int)sf_read_float(audioFile, buf, nb * channels); - for(int i = 0; i < nb; i++) sample[i] = buf[i * channels]; + int samplesRead = (int)sf_read_float(audioFile, buf, nb * channels); + for(int i = 0; i < nb; i++) samples[i] = buf[i * channels]; free(buf); - return samples / channels; + return samplesRead / channels; } } From 328ea956f40c3976390abf171f2a39f5783dbc22 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Tue, 16 Feb 2021 21:25:15 +0000 Subject: [PATCH 11/14] Export offsets as needed for image functions --- src/apt.h | 13 +++++++++++++ src/image.c | 23 +++++++++++------------ src/main.c | 39 +++++++++++++++++++-------------------- src/offsets.h | 29 ----------------------------- src/pngio.c | 38 +++++++++++++++++++------------------- src/pngio.h | 1 - 6 files changed, 62 insertions(+), 81 deletions(-) delete mode 100644 src/offsets.h diff --git a/src/apt.h b/src/apt.h index 022f00a..16aded7 100644 --- a/src/apt.h +++ b/src/apt.h @@ -41,6 +41,19 @@ extern "C" { // Maximum height of an APT image in number of scanlines #define APT_MAX_HEIGHT 3000 +#define APT_SYNC_WIDTH 39 +#define APT_SPC_WIDTH 47 +#define APT_TELE_WIDTH 45 +// Width in pixels of a single channel image +#define APT_CH_WIDTH 909 +#define APT_FRAME_LEN 128 +#define APT_CH_OFFSET (APT_SYNC_WIDTH+APT_SPC_WIDTH+APT_CH_WIDTH+APT_TELE_WIDTH) +#define APT_IMG_WIDTH 2080 +// Offset in pixels to channel A +#define APT_CHA_OFFSET (APT_SYNC_WIDTH+APT_SPC_WIDTH) +// Offset in pixels to channel B +#define APT_CHB_OFFSET (APT_SYNC_WIDTH+APT_SPC_WIDTH+APT_CH_WIDTH+APT_TELE_WIDTH+APT_SYNC_WIDTH+APT_SPC_WIDTH) +#define APT_TOTAL_TELE (APT_SYNC_WIDTH+APT_SPC_WIDTH+APT_TELE_WIDTH+APT_SYNC_WIDTH+APT_SPC_WIDTH+APT_TELE_WIDTH) // apt_getpixelrow callback function to get audio samples. // context is the same as passed to apt_getpixelrow. diff --git a/src/image.c b/src/image.c index 11f9e27..7c1fb5d 100644 --- a/src/image.c +++ b/src/image.c @@ -23,7 +23,6 @@ #include #include "apt.h" -#include "offsets.h" #include "libs/reg.h" #include "image.h" @@ -106,10 +105,10 @@ void apt_linearEnhance(float **prow, int nrow, int offset, int width){ // Brightness calibrate, including telemetry void calibrateImage(float **prow, int nrow, int offset, int width, rgparam_t regr){ - offset -= SYNC_WIDTH+SPC_WIDTH; + offset -= APT_SYNC_WIDTH+APT_SPC_WIDTH; for (int y = 0; y < nrow; y++) { - for (int x = 0; x < width+SYNC_WIDTH+SPC_WIDTH+TELE_WIDTH; x++) { + for (int x = 0; x < width+APT_SYNC_WIDTH+APT_SPC_WIDTH+APT_TELE_WIDTH; x++) { float pv = (float)rgcal(prow[y][x + offset], ®r); prow[y][x + offset] = CLIP(pv, 0, 255); } @@ -129,7 +128,7 @@ double teleNoise(double wedges[16]){ int apt_calibrate(float **prow, int nrow, int offset, int width) { double teleline[APT_MAX_HEIGHT] = { 0.0 }; double wedge[16]; - rgparam_t regr[APT_MAX_HEIGHT/FRAME_LEN + 1]; + rgparam_t regr[APT_MAX_HEIGHT/APT_FRAME_LEN + 1]; int telestart, mtelestart = 0; int channel = -1; @@ -166,10 +165,10 @@ int apt_calibrate(float **prow, int nrow, int offset, int width) { } } - telestart = (mtelestart + 64) % FRAME_LEN; + telestart = (mtelestart + 64) % APT_FRAME_LEN; // Make sure that theres at least one full frame in the image - if (nrow < telestart + FRAME_LEN) { + if (nrow < telestart + APT_FRAME_LEN) { fprintf(stderr, "Telemetry decoding error, not enough rows\n"); return 0; } @@ -177,7 +176,7 @@ int apt_calibrate(float **prow, int nrow, int offset, int width) { // Find the least noisy frame double minNoise = -1; int bestFrame = -1; - for (int n = telestart, k = 0; n < nrow - FRAME_LEN; n += FRAME_LEN, k++) { + for (int n = telestart, k = 0; n < nrow - APT_FRAME_LEN; n += APT_FRAME_LEN, k++) { int j; for (j = 0; j < 16; j++) { @@ -217,10 +216,10 @@ int apt_calibrate(float **prow, int nrow, int offset, int width) { // Find the brightness of the minute marker, I don't really know what for Cs = 0.0; int i, j = n; - for (i = 0, j = n; j < n + FRAME_LEN; j++) { + for (i = 0, j = n; j < n + APT_FRAME_LEN; j++) { float csline = 0.0; for (int l = 3; l < 43; l++) - csline += prow[n][l + offset - SPC_WIDTH]; + csline += prow[n][l + offset - APT_SPC_WIDTH]; csline /= 40.0; if (csline > 50.0) { @@ -286,10 +285,10 @@ int apt_cropNoise(apt_image_t *img){ float spc_rows[APT_MAX_HEIGHT] = { 0.0 }; int startCrop = 0; int endCrop = img->nrow; for(int y = 0; y < img->nrow; y++) { - for(int x = 0; x < SPC_WIDTH; x++) { - spc_rows[y] += img->prow[y][x + (CHB_OFFSET - SPC_WIDTH)]; + for(int x = 0; x < APT_SPC_WIDTH; x++) { + spc_rows[y] += img->prow[y][x + (APT_CHB_OFFSET - APT_SPC_WIDTH)]; } - spc_rows[y] /= SPC_WIDTH; + spc_rows[y] /= APT_SPC_WIDTH; // Skip minute markings if(spc_rows[y] < 10) { diff --git a/src/main.c b/src/main.c index 3b9ea07..0932587 100644 --- a/src/main.c +++ b/src/main.c @@ -31,7 +31,6 @@ #include #include "libs/argparse.h" -#include "offsets.h" #include "common.h" #include "apt.h" @@ -144,7 +143,7 @@ static int processAudio(char *filename, options_t *opts){ strncpy(img.name, ctime(&t), 24); // Init a row writer - initWriter(opts, &img, IMG_WIDTH, APT_MAX_HEIGHT, "Unprocessed realtime image", "r"); + initWriter(opts, &img, APT_IMG_WIDTH, APT_MAX_HEIGHT, "Unprocessed realtime image", "r"); } if(strcmp(extension, "png") == 0){ @@ -168,7 +167,7 @@ static int processAudio(char *filename, options_t *opts){ if (apt_getpixelrow(img.prow[img.nrow], img.nrow, &img.zenith, (img.nrow == 0), getsamples, NULL) == 0) break; - if(opts->realtime) pushRow(img.prow[img.nrow], IMG_WIDTH); + if(opts->realtime) pushRow(img.prow[img.nrow], APT_IMG_WIDTH); fprintf(stderr, "Row: %d\r", img.nrow); fflush(stderr); @@ -190,8 +189,8 @@ static int processAudio(char *filename, options_t *opts){ } // Calibrate - img.chA = apt_calibrate(img.prow, img.nrow, CHA_OFFSET, CH_WIDTH); - img.chB = apt_calibrate(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH); + img.chA = apt_calibrate(img.prow, img.nrow, APT_CHA_OFFSET, APT_CH_WIDTH); + img.chB = apt_calibrate(img.prow, img.nrow, APT_CHB_OFFSET, APT_CH_WIDTH); printf("Channel A: %s (%s)\n", ch.id[img.chA], ch.name[img.chA]); printf("Channel B: %s (%s)\n", ch.id[img.chB], ch.name[img.chB]); @@ -202,14 +201,14 @@ static int processAudio(char *filename, options_t *opts){ // Denoise if(CONTAINS(opts->effects, Denoise)){ - apt_denoise(img.prow, img.nrow, CHA_OFFSET, CH_WIDTH); - apt_denoise(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH); + apt_denoise(img.prow, img.nrow, APT_CHA_OFFSET, APT_CH_WIDTH); + apt_denoise(img.prow, img.nrow, APT_CHB_OFFSET, APT_CH_WIDTH); } // Flip, for northbound passes if(CONTAINS(opts->effects, Flip_Image)){ - apt_flipImage(&img, CH_WIDTH, CHA_OFFSET); - apt_flipImage(&img, CH_WIDTH, CHB_OFFSET); + apt_flipImage(&img, APT_CH_WIDTH, APT_CHA_OFFSET); + apt_flipImage(&img, APT_CH_WIDTH, APT_CHB_OFFSET); } // Temperature @@ -222,49 +221,49 @@ static int processAudio(char *filename, options_t *opts){ } // Perform temperature calibration - temperature(opts, &tmpimg, CHB_OFFSET, CH_WIDTH); - ImageOut(opts, &tmpimg, CHB_OFFSET, CH_WIDTH, "Temperature", Temperature, (char *)apt_TempPalette); + temperature(opts, &tmpimg, APT_CHB_OFFSET, APT_CH_WIDTH); + ImageOut(opts, &tmpimg, APT_CHB_OFFSET, APT_CH_WIDTH, "Temperature", Temperature, (char *)apt_TempPalette); } // MCIR if (CONTAINS(opts->type, MCIR)) - ImageOut(opts, &img, CHA_OFFSET, CH_WIDTH, "MCIR", MCIR, NULL); + ImageOut(opts, &img, APT_CHA_OFFSET, APT_CH_WIDTH, "MCIR", MCIR, NULL); // Linear equalise if(CONTAINS(opts->effects, Linear_Equalise)){ - apt_linearEnhance(img.prow, img.nrow, CHA_OFFSET, CH_WIDTH); - apt_linearEnhance(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH); + apt_linearEnhance(img.prow, img.nrow, APT_CHA_OFFSET, APT_CH_WIDTH); + apt_linearEnhance(img.prow, img.nrow, APT_CHB_OFFSET, APT_CH_WIDTH); } // Histogram equalise if(CONTAINS(opts->effects, Histogram_Equalise)){ - apt_histogramEqualise(img.prow, img.nrow, CHA_OFFSET, CH_WIDTH); - apt_histogramEqualise(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH); + apt_histogramEqualise(img.prow, img.nrow, APT_CHA_OFFSET, APT_CH_WIDTH); + apt_histogramEqualise(img.prow, img.nrow, APT_CHB_OFFSET, APT_CH_WIDTH); } // Raw image if (CONTAINS(opts->type, Raw_Image)) { sprintf(desc, "%s (%s) & %s (%s)", ch.id[img.chA], ch.name[img.chA], ch.id[img.chB], ch.name[img.chB]); - ImageOut(opts, &img, 0, IMG_WIDTH, desc, Raw_Image, NULL); + ImageOut(opts, &img, 0, APT_IMG_WIDTH, desc, Raw_Image, NULL); } // Palette image if (CONTAINS(opts->type, Palleted)) { img.palette = opts->palette; strcpy(desc, "Palette composite"); - ImageOut(opts, &img, CHA_OFFSET, 909, desc, Palleted, NULL); + ImageOut(opts, &img, APT_CHA_OFFSET, 909, desc, Palleted, NULL); } // Channel A if (CONTAINS(opts->type, Channel_A)) { sprintf(desc, "%s (%s)", ch.id[img.chA], ch.name[img.chA]); - ImageOut(opts, &img, CHA_OFFSET, CH_WIDTH, desc, Channel_A, NULL); + ImageOut(opts, &img, APT_CHA_OFFSET, APT_CH_WIDTH, desc, Channel_A, NULL); } // Channel B if (CONTAINS(opts->type, Channel_B)) { sprintf(desc, "%s (%s)", ch.id[img.chB], ch.name[img.chB]); - ImageOut(opts, &img, CHB_OFFSET, CH_WIDTH, desc, Channel_B, NULL); + ImageOut(opts, &img, APT_CHB_OFFSET, APT_CH_WIDTH, desc, Channel_B, NULL); } return 1; diff --git a/src/offsets.h b/src/offsets.h deleted file mode 100644 index 158f5de..0000000 --- a/src/offsets.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * This file is part of Aptdec. - * Copyright (c) 2004-2009 Thierry Leconte (F4DWV), Xerbo (xerbo@protonmail.com) 2019-2020 - * - * Aptdec is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -#define SYNC_WIDTH 39 -#define SPC_WIDTH 47 -#define TELE_WIDTH 45 -#define CH_WIDTH 909 -#define FRAME_LEN 128 -#define CH_OFFSET (SYNC_WIDTH+SPC_WIDTH+CH_WIDTH+TELE_WIDTH) -#define IMG_WIDTH 2080 -#define CHA_OFFSET (SYNC_WIDTH+SPC_WIDTH) -#define CHB_OFFSET (SYNC_WIDTH+SPC_WIDTH+CH_WIDTH+TELE_WIDTH+SYNC_WIDTH+SPC_WIDTH) -#define TOTAL_TELE (SYNC_WIDTH+SPC_WIDTH+TELE_WIDTH+SYNC_WIDTH+SPC_WIDTH+TELE_WIDTH) diff --git a/src/pngio.c b/src/pngio.c index d0aa95a..e605fd9 100644 --- a/src/pngio.c +++ b/src/pngio.c @@ -95,7 +95,7 @@ int mapOverlay(char *filename, apt_rgb_t **crow, int nrow, int zenith, int MCIR) }; // Pixel offsets - int chb = x + CHB_OFFSET - 49; + int chb = x + APT_CHB_OFFSET - 49; int cha = x + 36; // Fill in map @@ -170,8 +170,8 @@ int readRawImage(char *filename, float **prow, int *nrow) { png_byte bit_depth = png_get_bit_depth(png, info); // Check the image - if(width != IMG_WIDTH){ - fprintf(stderr, "Raw image must be %ipx wide.\n", IMG_WIDTH); + if(width != APT_IMG_WIDTH){ + fprintf(stderr, "Raw image must be %ipx wide.\n", APT_IMG_WIDTH); return 0; }else if(bit_depth != 8){ fprintf(stderr, "Raw image must have 8 bit color.\n"); @@ -281,9 +281,9 @@ int readPalette(char *filename, apt_rgb_t **pixels) { void prow2crow(float **prow, int nrow, char *palette, apt_rgb_t **crow){ for(int y = 0; y < nrow; y++){ - crow[y] = (apt_rgb_t *) malloc(sizeof(apt_rgb_t) * IMG_WIDTH); + crow[y] = (apt_rgb_t *) malloc(sizeof(apt_rgb_t) * APT_IMG_WIDTH); - for(int x = 0; x < IMG_WIDTH; x++){ + for(int x = 0; x < APT_IMG_WIDTH; x++){ if(palette == NULL) crow[y][x].r = crow[y][x].g = crow[y][x].b = prow[y][x]; else @@ -300,10 +300,10 @@ int applyUserPalette(float **prow, int nrow, char *filename, apt_rgb_t **crow){ } for(int y = 0; y < nrow; y++){ - for(int x = 0; x < CH_WIDTH; x++){ - int cha = CLIP(prow[y][x + CHA_OFFSET], 0, 255); - int chb = CLIP(prow[y][x + CHB_OFFSET], 0, 255); - crow[y][x + CHA_OFFSET] = pal_row[chb][cha]; + for(int x = 0; x < APT_CH_WIDTH; x++){ + int cha = CLIP(prow[y][x + APT_CHA_OFFSET], 0, 255); + int chb = CLIP(prow[y][x + APT_CHB_OFFSET], 0, 255); + crow[y][x + APT_CHA_OFFSET] = pal_row[chb][cha]; } } @@ -346,8 +346,8 @@ int ImageOut(options_t *opts, apt_image_t *img, int offset, int width, char *des for(unsigned long int i = 0; i < strlen(opts->effects); i++){ switch (opts->effects[i]) { case Crop_Telemetry: - width -= TOTAL_TELE; - offset += SYNC_WIDTH + SPC_WIDTH; + width -= APT_TOTAL_TELE; + offset += APT_SYNC_WIDTH + APT_SPC_WIDTH; crop_telemetry = 1; break; case Precipitation_Overlay: @@ -422,9 +422,9 @@ int ImageOut(options_t *opts, apt_image_t *img, int offset, int width, char *des // Precipitation overlay if(CONTAINS(opts->effects, Precipitation_Overlay)){ for(int y = 0; y < img->nrow; y++){ - for(int x = 0; x < CH_WIDTH; x++){ - if(img->prow[y][x + CHB_OFFSET] >= 198) - crow[y][x + CHB_OFFSET] = crow[y][x + CHA_OFFSET] = apt_applyPalette(apt_PrecipPalette, img->prow[y][x + CHB_OFFSET]-198); + for(int x = 0; x < APT_CH_WIDTH; x++){ + if(img->prow[y][x + APT_CHB_OFFSET] >= 198) + crow[y][x + APT_CHB_OFFSET] = crow[y][x + APT_CHA_OFFSET] = apt_applyPalette(apt_PrecipPalette, img->prow[y][x + APT_CHB_OFFSET]-198); } } } @@ -448,13 +448,13 @@ int ImageOut(options_t *opts, apt_image_t *img, int offset, int width, char *des // Build image for (int y = 0; y < img->nrow; y++) { - png_color pix[IMG_WIDTH]; // Color - png_byte mpix[IMG_WIDTH]; // Mono + png_color pix[APT_IMG_WIDTH]; // Color + png_byte mpix[APT_IMG_WIDTH]; // Mono int skip = 0; for (int x = 0; x < width; x++) { - if(crop_telemetry && x == CH_WIDTH) - skip += TELE_WIDTH + SYNC_WIDTH + SPC_WIDTH; + if(crop_telemetry && x == APT_CH_WIDTH) + skip += APT_TELE_WIDTH + APT_SYNC_WIDTH + APT_SPC_WIDTH; if(greyscale){ mpix[x] = POWF(img->prow[y][x + skip + offset], opts->gamma)/a; @@ -538,7 +538,7 @@ int initWriter(options_t *opts, apt_image_t *img, int width, int height, char *d } void pushRow(float *row, int width){ - png_byte pix[IMG_WIDTH]; + png_byte pix[APT_IMG_WIDTH]; for(int i = 0; i < width; i++) pix[i] = row[i]; diff --git a/src/pngio.h b/src/pngio.h index f52482a..193cbdf 100644 --- a/src/pngio.h +++ b/src/pngio.h @@ -1,6 +1,5 @@ #include "apt.h" #include "common.h" -#include "offsets.h" int mapOverlay(char *filename, apt_rgb_t **crow, int nrow, int zenith, int MCIR); int readRawImage(char *filename, float **prow, int *nrow); From 612dc0a9776578896aae7af2537ff19c7661efc1 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Tue, 16 Feb 2021 21:48:22 +0000 Subject: [PATCH 12/14] Add macro for width of pixel rows --- src/apt.h | 7 +++++++ src/image.c | 2 +- src/main.c | 6 +++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/apt.h b/src/apt.h index 16aded7..e1429df 100644 --- a/src/apt.h +++ b/src/apt.h @@ -41,13 +41,17 @@ extern "C" { // Maximum height of an APT image in number of scanlines #define APT_MAX_HEIGHT 3000 +// Width in pixels of sync #define APT_SYNC_WIDTH 39 +// Width in pixels of space #define APT_SPC_WIDTH 47 +// Width in pixels of telemetry #define APT_TELE_WIDTH 45 // Width in pixels of a single channel image #define APT_CH_WIDTH 909 #define APT_FRAME_LEN 128 #define APT_CH_OFFSET (APT_SYNC_WIDTH+APT_SPC_WIDTH+APT_CH_WIDTH+APT_TELE_WIDTH) +// Width in pixels of full frame, including sync, space, images and telemetry #define APT_IMG_WIDTH 2080 // Offset in pixels to channel A #define APT_CHA_OFFSET (APT_SYNC_WIDTH+APT_SPC_WIDTH) @@ -55,6 +59,9 @@ extern "C" { #define APT_CHB_OFFSET (APT_SYNC_WIDTH+APT_SPC_WIDTH+APT_CH_WIDTH+APT_TELE_WIDTH+APT_SYNC_WIDTH+APT_SPC_WIDTH) #define APT_TOTAL_TELE (APT_SYNC_WIDTH+APT_SPC_WIDTH+APT_TELE_WIDTH+APT_SYNC_WIDTH+APT_SPC_WIDTH+APT_TELE_WIDTH) +// Width in elements of apt_image_t.prow arrays +#define APT_PROW_WIDTH 2150 + // apt_getpixelrow callback function to get audio samples. // context is the same as passed to apt_getpixelrow. typedef int (*apt_getsamples_t)(void *context, float *samples, int count); diff --git a/src/image.c b/src/image.c index 7c1fb5d..712cc17 100644 --- a/src/image.c +++ b/src/image.c @@ -318,7 +318,7 @@ int apt_cropNoise(apt_image_t *img){ // Remove the noisy rows at start for(int y = 0; y < img->nrow-startCrop; y++) { - memmove(img->prow[y], img->prow[y+startCrop], sizeof(float)*2150); + memmove(img->prow[y], img->prow[y+startCrop], sizeof(float)*APT_PROW_WIDTH); } // Ignore the noisy rows at the end diff --git a/src/main.c b/src/main.c index 0932587..677487d 100644 --- a/src/main.c +++ b/src/main.c @@ -161,7 +161,7 @@ static int processAudio(char *filename, options_t *opts){ // TODO: multithreading, would require some sort of input buffer for (img.nrow = 0; img.nrow < APT_MAX_HEIGHT; img.nrow++) { // Allocate memory for this row - img.prow[img.nrow] = (float *) malloc(sizeof(float) * 2150); + img.prow[img.nrow] = (float *) malloc(sizeof(float) * APT_PROW_WIDTH); // Write into memory and break the loop when there are no more samples to read if (apt_getpixelrow(img.prow[img.nrow], img.nrow, &img.zenith, (img.nrow == 0), getsamples, NULL) == 0) @@ -216,8 +216,8 @@ static int processAudio(char *filename, options_t *opts){ // Create another buffer as to not modify the orignal apt_image_t tmpimg = img; for(int i = 0; i < img.nrow; i++){ - tmpimg.prow[i] = (float *) malloc(sizeof(float) * 2150); - memcpy(tmpimg.prow[i], img.prow[i], sizeof(float) * 2150); + tmpimg.prow[i] = (float *) malloc(sizeof(float) * APT_PROW_WIDTH); + memcpy(tmpimg.prow[i], img.prow[i], sizeof(float) * APT_PROW_WIDTH); } // Perform temperature calibration From b3dd3f8ce148d802c9b281c3c3e49684d73a2bb7 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Wed, 17 Feb 2021 10:45:18 +0000 Subject: [PATCH 13/14] Add enum for channel ID. Fix channel 3A to be near-IR as per https://nssdc.gsfc.nasa.gov/nmc/experiment/display.action?id=1998-030A-01 --- src/apt.h | 18 +++++++++++++++--- src/image.c | 12 ++++++------ src/main.c | 2 +- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/apt.h b/src/apt.h index e1429df..3f12618 100644 --- a/src/apt.h +++ b/src/apt.h @@ -39,7 +39,7 @@ extern "C" { #define APT_API #endif -// Maximum height of an APT image in number of scanlines +// Maximum height of an APT image in number of rows #define APT_MAX_HEIGHT 3000 // Width in pixels of sync #define APT_SYNC_WIDTH 39 @@ -59,6 +59,18 @@ extern "C" { #define APT_CHB_OFFSET (APT_SYNC_WIDTH+APT_SPC_WIDTH+APT_CH_WIDTH+APT_TELE_WIDTH+APT_SYNC_WIDTH+APT_SPC_WIDTH) #define APT_TOTAL_TELE (APT_SYNC_WIDTH+APT_SPC_WIDTH+APT_TELE_WIDTH+APT_SYNC_WIDTH+APT_SPC_WIDTH+APT_TELE_WIDTH) +// Number of rows required for apt_calibrate +#define APT_CALIBRATION_ROWS 192 +// Channel ID returned by apt_calibrate +// NOAA-15: https://nssdc.gsfc.nasa.gov/nmc/experiment/display.action?id=1998-030A-01 +// Channel 1: visible (0.58-0.68 um) +// Channel 2: near-IR (0.725-1.0 um) +// Channel 3A: near-IR (1.58-1.64 um) +// Channel 3B: mid-infrared (3.55-3.93 um) +// Channel 4: thermal-infrared (10.3-11.3 um) +// Channel 5: thermal-infrared (11.5-12.5 um) +typedef enum apt_channel {APT_CHANNEL_UNKNOWN, APT_CHANNEL_1, APT_CHANNEL_2, APT_CHANNEL_3A, APT_CHANNEL_4, APT_CHANNEL_5, APT_CHANNEL_3B} apt_channel_t; + // Width in elements of apt_image_t.prow arrays #define APT_PROW_WIDTH 2150 @@ -70,7 +82,7 @@ typedef struct { float *prow[APT_MAX_HEIGHT]; // Row buffers int nrow; // Number of rows int zenith; // Row in image where satellite reaches peak elevation - int chA, chB; // ID of each channel + apt_channel_t chA, chB; // ID of each channel char name[256]; // Stripped filename char *palette; // Filename of palette } apt_image_t; @@ -84,7 +96,7 @@ int APT_API apt_getpixelrow(float *pixelv, int nrow, int *zenith, int reset, apt void APT_API apt_histogramEqualise(float **prow, int nrow, int offset, int width); void APT_API apt_linearEnhance(float **prow, int nrow, int offset, int width); -int APT_API apt_calibrate(float **prow, int nrow, int offset, int width) ; +apt_channel_t APT_API apt_calibrate(float **prow, int nrow, int offset, int width) ; void APT_API apt_denoise(float **prow, int nrow, int offset, int width); void APT_API apt_flipImage(apt_image_t *img, int width, int offset); int APT_API apt_cropNoise(apt_image_t *img); diff --git a/src/image.c b/src/image.c index 712cc17..11a2ef9 100644 --- a/src/image.c +++ b/src/image.c @@ -125,7 +125,7 @@ double teleNoise(double wedges[16]){ } // Get telemetry data for thermal calibration -int apt_calibrate(float **prow, int nrow, int offset, int width) { +apt_channel_t apt_calibrate(float **prow, int nrow, int offset, int width) { double teleline[APT_MAX_HEIGHT] = { 0.0 }; double wedge[16]; rgparam_t regr[APT_MAX_HEIGHT/APT_FRAME_LEN + 1]; @@ -133,9 +133,9 @@ int apt_calibrate(float **prow, int nrow, int offset, int width) { int channel = -1; // The minimum rows required to decode a full frame - if (nrow < 192) { + if (nrow < APT_CALIBRATION_ROWS) { fprintf(stderr, "Telemetry decoding error, not enough rows\n"); - return 0; + return APT_CHANNEL_UNKNOWN; } // Calculate average of a row of telemetry @@ -170,7 +170,7 @@ int apt_calibrate(float **prow, int nrow, int offset, int width) { // Make sure that theres at least one full frame in the image if (nrow < telestart + APT_FRAME_LEN) { fprintf(stderr, "Telemetry decoding error, not enough rows\n"); - return 0; + return APT_CHANNEL_UNKNOWN; } // Find the least noisy frame @@ -233,12 +233,12 @@ int apt_calibrate(float **prow, int nrow, int offset, int width) { if(bestFrame == -1){ fprintf(stderr, "Something has gone very wrong, please file a bug report.\n"); - return 0; + return APT_CHANNEL_UNKNOWN; } calibrateImage(prow, nrow, offset, width, regr[bestFrame]); - return channel + 1; + return (apt_channel_t)(channel + 1); } diff --git a/src/main.c b/src/main.c index 677487d..abb0069 100644 --- a/src/main.c +++ b/src/main.c @@ -124,7 +124,7 @@ static int processAudio(char *filename, options_t *opts){ char *name[7]; } ch = { { "?", "1", "2", "3A", "4", "5", "3B" }, - { "unknown", "visble", "near-infrared", "mid-infrared", "thermal-infrared", "thermal-infrared", "mid-infrared" } + { "unknown", "visble", "near-infrared", "near-infrared", "thermal-infrared", "thermal-infrared", "mid-infrared" } }; // Buffer for image channel From 72ce791a56b7515994e1d08cadde46e9fc6104d4 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Thu, 18 Feb 2021 19:54:54 +0000 Subject: [PATCH 14/14] Fix error in release build --- src/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.c b/src/main.c index abb0069..56c487b 100644 --- a/src/main.c +++ b/src/main.c @@ -299,6 +299,7 @@ static int initsnd(char *filename) { // Read samples from the audio file int getsamples(void *context, float *samples, int nb) { + (void) context; if(channels == 1){ return (int)sf_read_float(audioFile, samples, nb); }else{