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.tags/v1.8.0
@@ -2,33 +2,53 @@ cmake_minimum_required (VERSION 3.0.0) | |||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") | ||||
project(aptdec) | 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") | 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() | 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() | 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() | endif() | ||||
# libsndfile | |||||
find_package(LibSndFile REQUIRED) | |||||
target_link_libraries(aptdec PRIVATE ${LIBSNDFILE_LIBRARY}) | |||||
# TODO: get this from git | # TODO: get this from git | ||||
set(PROJECT_VERSION "1.7.0") | set(PROJECT_VERSION "1.7.0") | ||||
@@ -45,16 +65,25 @@ IF(NOT WIN32) | |||||
set(CPACK_GENERATOR "DEB;TGZ") | set(CPACK_GENERATOR "DEB;TGZ") | ||||
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}.${CMAKE_SYSTEM_PROCESSOR}") | 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() | else() | ||||
#set(CPACK_GENERATOR "ZIP;NSIS") | #set(CPACK_GENERATOR "ZIP;NSIS") | ||||
set(CPACK_GENERATOR "ZIP") | set(CPACK_GENERATOR "ZIP") | ||||
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") | 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/") | install(DIRECTORY "${PROJECT_SOURCE_DIR}/palettes/" DESTINATION "palettes/") | ||||
endif() | endif() | ||||
@@ -129,11 +129,18 @@ cmake .. | |||||
make | 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 | 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 | ## Further Reading | ||||
[User's Guide for Building and Operating | [User's Guide for Building and Operating | ||||
@@ -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 ../.. |
@@ -1,3 +1,6 @@ | |||||
#!/bin/bash | |||||
# Cross compile for Windows from Linux | |||||
TEMP_PATH="$(pwd)/winpath" | TEMP_PATH="$(pwd)/winpath" | ||||
set -e | set -e | ||||
@@ -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 <https://www.gnu.org/licenses/>. | |||||
* | |||||
*/ | |||||
#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 |
@@ -17,18 +17,19 @@ | |||||
* | * | ||||
*/ | */ | ||||
#include "apt.h" | |||||
#include "color.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 + 0], | ||||
palette[(int)CLIP(val, 0, 255)*3 + 1], | palette[(int)CLIP(val, 0, 255)*3 + 1], | ||||
palette[(int)CLIP(val, 0, 255)*3 + 2] | 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.r, top_a, bottom.r, bottom_a), | ||||
MCOMPOSITE(top.g, top_a, bottom.g, bottom_a), | MCOMPOSITE(top.g, top_a, bottom.g, bottom_a), | ||||
MCOMPOSITE(top.b, top_a, bottom.b, bottom_a) | MCOMPOSITE(top.b, top_a, bottom.b, bottom_a) | ||||
@@ -1,9 +1,3 @@ | |||||
#include "common.h" | #include "common.h" | ||||
#define MCOMPOSITE(m1, a1, m2, a2) (m1*a1 + m2*a2*(1-a1)) | #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]; |
@@ -19,7 +19,6 @@ | |||||
// Constants | // Constants | ||||
#define VERSION "Aptdec; (c) 2004-2009 Thierry Leconte F4DWV, Xerbo (xerbo@protonmail.com) 2019-2020" | #define VERSION "Aptdec; (c) 2004-2009 Thierry Leconte F4DWV, Xerbo (xerbo@protonmail.com) 2019-2020" | ||||
#define MAX_HEIGHT 3000 | |||||
// Useful macros | // Useful macros | ||||
#define CLIP(v, lo, hi) (v > hi ? hi : (v > lo ? v : lo)) | #define CLIP(v, lo, hi) (v > hi ? hi : (v > lo ? v : lo)) | ||||
@@ -28,17 +27,6 @@ | |||||
// Typedefs | // Typedefs | ||||
#ifndef STRUCTS_DEFINED | #ifndef STRUCTS_DEFINED | ||||
#define 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 { | typedef struct { | ||||
char *type; // Output image type | char *type; // Output image type | ||||
char *effects; // Effects on the image | char *effects; // Effects on the image | ||||
@@ -70,4 +58,5 @@ enum effects { | |||||
Linear_Equalise='l', | Linear_Equalise='l', | ||||
Crop_Noise='c' | Crop_Noise='c' | ||||
}; | }; | ||||
#endif | #endif |
@@ -22,6 +22,7 @@ | |||||
#include <string.h> | #include <string.h> | ||||
#include <math.h> | #include <math.h> | ||||
#include "apt.h" | |||||
#include "filter.h" | #include "filter.h" | ||||
// In case your C compiler is so old that Pi hadn't been invented yet | // In case your C compiler is so old that Pi hadn't been invented yet | ||||
@@ -40,8 +41,6 @@ | |||||
#define RSMULT 15 | #define RSMULT 15 | ||||
#define Fi (Fp * RSMULT) | #define Fi (Fp * RSMULT) | ||||
extern int getsample(float *inbuff, int count); | |||||
static double Fe; | static double Fe; | ||||
static double offset = 0.0; | static double offset = 0.0; | ||||
@@ -51,7 +50,7 @@ static double FreqOsc; | |||||
static double K1, K2; | static double K1, K2; | ||||
// Check the sample rate and calculate some constants | // 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 > Fi) return 1; | ||||
if(F < Fp) return -1; | if(F < Fp) return -1; | ||||
Fe = F; | Fe = F; | ||||
@@ -132,7 +131,7 @@ static double pll(double I, double Q) { | |||||
} | } | ||||
// Convert samples into pixels | // 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 float inbuff[BLKIN]; | ||||
static int idxin = 0; | static int idxin = 0; | ||||
static int nin = 0; | static int nin = 0; | ||||
@@ -169,7 +168,7 @@ static int getamp(double *ampbuff, int count) { | |||||
} | } | ||||
// Sub-pixel offsetting + FIR compensation | // Sub-pixel offsetting + FIR compensation | ||||
int getpixelv(float *pvbuff, int count) { | |||||
int getpixelv(float *pvbuff, int count, apt_getsample_t getsample) { | |||||
// Amplitude buffer | // Amplitude buffer | ||||
static double ampbuff[BLKAMP]; | static double ampbuff[BLKAMP]; | ||||
static int nam = 0; | static int nam = 0; | ||||
@@ -179,7 +178,7 @@ int getpixelv(float *pvbuff, int count) { | |||||
// Gaussian resampling factor | // Gaussian resampling factor | ||||
mult = (double) Fi / Fe * FreqLine; | mult = (double) Fi / Fe * FreqLine; | ||||
int m = RSFilterLen / mult + 1; | |||||
int m = (int)(RSFilterLen / mult + 1); | |||||
for (int n = 0; n < count; n++) { | for (int n = 0; n < count; n++) { | ||||
int shift; | int shift; | ||||
@@ -188,14 +187,14 @@ int getpixelv(float *pvbuff, int count) { | |||||
int res; | int res; | ||||
memmove(ampbuff, &(ampbuff[idxam]), nam * sizeof(double)); | memmove(ampbuff, &(ampbuff[idxam]), nam * sizeof(double)); | ||||
idxam = 0; | idxam = 0; | ||||
res = getamp(&(ampbuff[nam]), BLKAMP - nam); | |||||
res = getamp(&(ampbuff[nam]), BLKAMP - nam, getsample); | |||||
nam += res; | nam += res; | ||||
if (nam < m) | if (nam < m) | ||||
return n; | return n; | ||||
} | } | ||||
// Gaussian FIR compensation filter | // 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; | shift = ((int) floor((RSMULT - offset) / mult)) + 1; | ||||
offset = shift * mult + offset - RSMULT; | 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 | // 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 float pixels[PixelLine + SyncFilterLen]; | ||||
static int npv; | static int npv; | ||||
static int synced = 0; | static int synced = 0; | ||||
@@ -226,7 +225,7 @@ int getpixelrow(float *pixelv, int nrow, int *zenith, int reset) { | |||||
// Get the sync line | // Get the sync line | ||||
if (npv < SyncFilterLen + 2) { | if (npv < SyncFilterLen + 2) { | ||||
res = getpixelv(&(pixelv[npv]), SyncFilterLen + 2 - npv); | |||||
res = getpixelv(&(pixelv[npv]), SyncFilterLen + 2 - npv, getsample); | |||||
npv += res; | npv += res; | ||||
if (npv < SyncFilterLen + 2) | if (npv < SyncFilterLen + 2) | ||||
return 0; | return 0; | ||||
@@ -257,7 +256,7 @@ int getpixelrow(float *pixelv, int nrow, int *zenith, int reset) { | |||||
static int lastmshift; | static int lastmshift; | ||||
if (npv < PixelLine + SyncFilterLen) { | if (npv < PixelLine + SyncFilterLen) { | ||||
res = getpixelv(&(pixelv[npv]), PixelLine + SyncFilterLen - npv); | |||||
res = getpixelv(&(pixelv[npv]), PixelLine + SyncFilterLen - npv, getsample); | |||||
npv += res; | npv += res; | ||||
if (npv < PixelLine + SyncFilterLen) | if (npv < PixelLine + SyncFilterLen) | ||||
return 0; | return 0; | ||||
@@ -295,7 +294,7 @@ int getpixelrow(float *pixelv, int nrow, int *zenith, int reset) { | |||||
// Get the rest of this row | // Get the rest of this row | ||||
if (npv < PixelLine) { | if (npv < PixelLine) { | ||||
res = getpixelv(&(pixelv[npv]), PixelLine - npv); | |||||
res = getpixelv(&(pixelv[npv]), PixelLine - npv, getsample); | |||||
npv += res; | npv += res; | ||||
if (npv < PixelLine) | if (npv < PixelLine) | ||||
return 0; | return 0; | ||||
@@ -27,7 +27,7 @@ float fir(float *buff, const float *coeff, const int len) { | |||||
for (int i = 0; i < len; i++) { | for (int i = 0; i < len; i++) { | ||||
r += buff[i] * coeff[i]; | r += buff[i] * coeff[i]; | ||||
} | } | ||||
return r; | |||||
return (float)r; | |||||
} | } | ||||
/* IQ finite impulse response | /* IQ finite impulse response | ||||
@@ -61,5 +61,5 @@ float rsfir(double *buff, const float *coeff, const int len, const double offset | |||||
alpha = n - k; | alpha = n - k; | ||||
out += buff[i] * (coeff[k] * (1.0 - alpha) + coeff[k + 1] * alpha); | out += buff[i] * (coeff[k] * (1.0 - alpha) + coeff[k + 1] * alpha); | ||||
} | } | ||||
return out; | |||||
return (float)out; | |||||
} | } |
@@ -19,10 +19,10 @@ | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <sndfile.h> | |||||
#include <math.h> | #include <math.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include "apt.h" | |||||
#include "offsets.h" | #include "offsets.h" | ||||
#include "libs/reg.h" | #include "libs/reg.h" | ||||
#include "image.h" | #include "image.h" | ||||
@@ -55,7 +55,7 @@ static double rgcal(float x, rgparam_t *rgpr) { | |||||
static double tele[16]; | static double tele[16]; | ||||
static double Cs; | 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 | // Plot histogram | ||||
int histogram[256] = { 0 }; | int histogram[256] = { 0 }; | ||||
for(int y = 0; y < nrow; y++) | 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; | int area = nrow * width; | ||||
for(int y = 0; y < nrow; y++){ | for(int y = 0; y < nrow; y++){ | ||||
for(int x = 0; x < width; x++){ | 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 | // Plot histogram | ||||
int histogram[256] = { 0 }; | int histogram[256] = { 0 }; | ||||
for(int y = 0; y < nrow; y++) | 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 | // Stretch the brightness into the new range | ||||
for(int y = 0; y < nrow; y++){ | for(int y = 0; y < nrow; y++){ | ||||
for(int x = 0; x < width; x++){ | 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 y = 0; y < nrow; y++) { | ||||
for (int x = 0; x < width+SYNC_WIDTH+SPC_WIDTH+TELE_WIDTH; x++) { | 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); | prow[y][x + offset] = CLIP(pv, 0, 255); | ||||
} | } | ||||
} | } | ||||
@@ -126,10 +126,10 @@ double teleNoise(double wedges[16]){ | |||||
} | } | ||||
// Get telemetry data for thermal calibration | // 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]; | 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 telestart, mtelestart = 0; | ||||
int channel = -1; | int channel = -1; | ||||
@@ -156,8 +156,8 @@ int calibrate(float **prow, int nrow, int offset, int width) { | |||||
float df; | float df; | ||||
// (sum 4px below) - (sum 4px above) | // (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 | // Find the maximum difference | ||||
if (df > max) { | if (df > max) { | ||||
@@ -197,7 +197,7 @@ int calibrate(float **prow, int nrow, int offset, int width) { | |||||
// Compute & apply regression on the wedges | // Compute & apply regression on the wedges | ||||
rgcomp(wedge, ®r[k]); | rgcomp(wedge, ®r[k]); | ||||
for (int j = 0; j < 16; j++) | 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 | /* Compare the channel ID wedge to the reference | ||||
* wedges, the wedge with the closest match will | * 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; | float min = -1; | ||||
for (int j = 0; j < 6; j++) { | for (int j = 0; j < 6; j++) { | ||||
float df = tele[15] - tele[j]; | |||||
float df = (float)(tele[15] - tele[j]); | |||||
df *= df; | df *= df; | ||||
if (df < min || min == -1) { | if (df < min || min == -1) { | ||||
@@ -228,7 +228,7 @@ int calibrate(float **prow, int nrow, int offset, int width) { | |||||
i++; | 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 | // Biased median denoise, pretyt ugly | ||||
#define TRIG_LEVEL 40 | #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 y = 2; y < nrow-2; y++){ | ||||
for(int x = offset+1; x < offset+width-1; x++){ | for(int x = offset+1; x < offset+width-1; x++){ | ||||
if(prow[y][x+1] - prow[y][x] > TRIG_LEVEL || | 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 | #undef TRIG_LEVEL | ||||
// Flips a channel, for northbound passes | // 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 y = 1; y < img->nrow; y++){ | ||||
for(int x = 1; x < ceil(width / 2.0); x++){ | for(int x = 1; x < ceil(width / 2.0); x++){ | ||||
// Flip top-left & bottom-right | // 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 | // 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 | #define NOISE_THRESH 180.0 | ||||
// Average value of minute marker | // 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; | int startCrop = 0; int endCrop = img->nrow; | ||||
for(int y = 0; y < img->nrow; y++) { | for(int y = 0; y < img->nrow; y++) { | ||||
for(int x = 0; x < SPC_WIDTH; x++) { | 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 | // 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; | tempparam_t temp; | ||||
printf("Temperature... "); | 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 y = 0; y < img->nrow; y++) { | ||||
for (int x = 0; x < width; x++) { | 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"); | printf("Done\n"); | ||||
@@ -1,9 +1,4 @@ | |||||
#include "apt.h" | |||||
#include "common.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); |
@@ -20,7 +20,11 @@ | |||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <string.h> | #include <string.h> | ||||
#ifndef _MSC_VER | |||||
#include <libgen.h> | #include <libgen.h> | ||||
#else | |||||
#include <windows.h> | |||||
#endif | |||||
#include <math.h> | #include <math.h> | ||||
#include <sndfile.h> | #include <sndfile.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
@@ -28,10 +32,8 @@ | |||||
#include "libs/argparse.h" | #include "libs/argparse.h" | ||||
#include "offsets.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 "pngio.h" | ||||
#include "image.h" | #include "image.h" | ||||
@@ -47,6 +49,23 @@ static int initsnd(char *filename); | |||||
int getsample(float *sample, int nb); | int getsample(float *sample, int nb); | ||||
static int processAudio(char *filename, options_t *opts); | 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) { | int main(int argc, const char **argv) { | ||||
options_t opts = { "r", "", 19, "", ".", 0, "", "", 1.0, 0 }; | 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){ | static int processAudio(char *filename, options_t *opts){ | ||||
// Image info struct | // Image info struct | ||||
image_t img; | |||||
apt_image_t img; | |||||
// Mapping between wedge value and channel ID | // Mapping between wedge value and channel ID | ||||
static struct { | static struct { | ||||
@@ -125,7 +144,7 @@ static int processAudio(char *filename, options_t *opts){ | |||||
strncpy(img.name, ctime(&t), 24); | strncpy(img.name, ctime(&t), 24); | ||||
// Init a row writer | // 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){ | if(strcmp(extension, "png") == 0){ | ||||
@@ -141,12 +160,12 @@ static int processAudio(char *filename, options_t *opts){ | |||||
// Build image | // Build image | ||||
// TODO: multithreading, would require some sort of input buffer | // 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 | // Allocate memory for this row | ||||
img.prow[img.nrow] = (float *) malloc(sizeof(float) * 2150); | img.prow[img.nrow] = (float *) malloc(sizeof(float) * 2150); | ||||
// Write into memory and break the loop when there are no more samples to read | // 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; | break; | ||||
if(opts->realtime) pushRow(img.prow[img.nrow], IMG_WIDTH); | if(opts->realtime) pushRow(img.prow[img.nrow], IMG_WIDTH); | ||||
@@ -171,32 +190,32 @@ static int processAudio(char *filename, options_t *opts){ | |||||
} | } | ||||
// Calibrate | // 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 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]); | printf("Channel B: %s (%s)\n", ch.id[img.chB], ch.name[img.chB]); | ||||
// Crop noise from start and end of image | // Crop noise from start and end of image | ||||
if(CONTAINS(opts->effects, Crop_Noise)){ | if(CONTAINS(opts->effects, Crop_Noise)){ | ||||
img.zenith -= cropNoise(&img); | |||||
img.zenith -= apt_cropNoise(&img); | |||||
} | } | ||||
// Denoise | // Denoise | ||||
if(CONTAINS(opts->effects, 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 | // Flip, for northbound passes | ||||
if(CONTAINS(opts->effects, Flip_Image)){ | 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 | // Temperature | ||||
if (CONTAINS(opts->type, Temperature) && img.chB >= 4) { | if (CONTAINS(opts->type, Temperature) && img.chB >= 4) { | ||||
// Create another buffer as to not modify the orignal | // 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++){ | for(int i = 0; i < img.nrow; i++){ | ||||
tmpimg.prow[i] = (float *) malloc(sizeof(float) * 2150); | tmpimg.prow[i] = (float *) malloc(sizeof(float) * 2150); | ||||
memcpy(tmpimg.prow[i], img.prow[i], 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 | // Perform temperature calibration | ||||
temperature(opts, &tmpimg, CHB_OFFSET, CH_WIDTH); | 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 | // MCIR | ||||
@@ -213,14 +232,14 @@ static int processAudio(char *filename, options_t *opts){ | |||||
// Linear equalise | // Linear equalise | ||||
if(CONTAINS(opts->effects, 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 | // Histogram equalise | ||||
if(CONTAINS(opts->effects, 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 | // Raw image | ||||
@@ -263,7 +282,7 @@ static int initsnd(char *filename) { | |||||
return 0; | return 0; | ||||
} | } | ||||
res = init_dsp(infwav.samplerate); | |||||
res = apt_init(infwav.samplerate); | |||||
printf("Input file: %s\n", filename); | printf("Input file: %s\n", filename); | ||||
if(res < 0) { | if(res < 0) { | ||||
fprintf(stderr, "Input sample rate too low: %d\n", infwav.samplerate); | 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 | // Read samples from the audio file | ||||
int getsample(float *sample, int nb) { | int getsample(float *sample, int nb) { | ||||
if(channels == 1){ | if(channels == 1){ | ||||
return sf_read_float(audioFile, sample, nb); | |||||
return (int)sf_read_float(audioFile, sample, nb); | |||||
}else{ | }else{ | ||||
/* Multi channel audio is encoded such as: | /* Multi channel audio is encoded such as: | ||||
* Ch1,Ch2,Ch1,Ch2,Ch1,Ch2 | * 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]; | for(int i = 0; i < nb; i++) sample[i] = buf[i * channels]; | ||||
free(buf); | |||||
return samples / channels; | return samples / channels; | ||||
} | } | ||||
} | } |
@@ -26,7 +26,7 @@ | |||||
#include "pngio.h" | #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"); | FILE *fp = fopen(filename, "rb"); | ||||
if(!fp) { | if(!fp) { | ||||
fprintf(stderr, "Cannot open %s\n", filename); | 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++){ | for(int x = 49; x < width - 82; x++){ | ||||
// Maps are 16 bit / channel | // Maps are 16 bit / channel | ||||
png_bytep px = &mapRows[CLIP(y + mapOffset, 0, height-1)][x * 6]; | 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[0] << 8) | px[1], | ||||
(px[2] << 8) | px[3], | (px[2] << 8) | px[3], | ||||
(px[4] << 8) | px[5] | (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 darken = ((255-crow[y][chb].r)-100)/50; | ||||
float green = CLIP(map.g/300, 0, 1); | float green = CLIP(map.g/300, 0, 1); | ||||
float blue = 0.15 - CLIP(map.b/960.0, 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{ | }else{ | ||||
// Sea | // 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.b = CLIP(map.b, 0, 255.0); | ||||
// Map overlay on channel A | // 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 | // Map overlay on channel B | ||||
if(!MCIR) | 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 | // Cloud overlay on channel A | ||||
if(MCIR){ | if(MCIR){ | ||||
float cloud = CLIP((crow[y][chb].r - 113) / 90.0, 0, 1); | 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; | return 1; | ||||
} | } | ||||
int readPalette(char *filename, rgb_t **pixels) { | |||||
int readPalette(char *filename, apt_rgb_t **pixels) { | |||||
FILE *fp = fopen(filename, "rb"); | FILE *fp = fopen(filename, "rb"); | ||||
if(!fp) { | if(!fp) { | ||||
char buffer[1024]; | char buffer[1024]; | ||||
@@ -266,10 +266,10 @@ int readPalette(char *filename, rgb_t **pixels) { | |||||
// Put into crow | // Put into crow | ||||
for(int y = 0; y < height; y++) { | 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++) | 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], | ||||
PNGrows[y][x*3 + 1], | PNGrows[y][x*3 + 1], | ||||
PNGrows[y][x*3 + 2] | PNGrows[y][x*3 + 2] | ||||
@@ -279,21 +279,21 @@ int readPalette(char *filename, rgb_t **pixels) { | |||||
return 1; | 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++){ | 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++){ | for(int x = 0; x < IMG_WIDTH; x++){ | ||||
if(palette == NULL) | if(palette == NULL) | ||||
crow[y][x].r = crow[y][x].g = crow[y][x].b = prow[y][x]; | crow[y][x].r = crow[y][x].g = crow[y][x].b = prow[y][x]; | ||||
else | 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)){ | if(!readPalette(filename, pal_row)){ | ||||
fprintf(stderr, "Could not read palette\n"); | fprintf(stderr, "Could not read palette\n"); | ||||
return 0; | return 0; | ||||
@@ -310,7 +310,7 @@ int applyUserPalette(float **prow, int nrow, char *filename, rgb_t **crow){ | |||||
return 1; | 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]; | char outName[512]; | ||||
if(opts->filename == NULL || opts->filename[0] == '\0'){ | if(opts->filename == NULL || opts->filename[0] == '\0'){ | ||||
sprintf(outName, "%s/%s-%c.png", opts->path, img->name, chid); | 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); | png_write_info(png_ptr, info_ptr); | ||||
// Move prow into crow, crow ~ color rows, if required | // Move prow into crow, crow ~ color rows, if required | ||||
rgb_t *crow[MAX_HEIGHT]; | |||||
apt_rgb_t *crow[APT_MAX_HEIGHT]; | |||||
if(!greyscale){ | if(!greyscale){ | ||||
prow2crow(img->prow, img->nrow, palette, crow); | 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 y = 0; y < img->nrow; y++){ | ||||
for(int x = 0; x < CH_WIDTH; x++){ | for(int x = 0; x < CH_WIDTH; x++){ | ||||
if(img->prow[y][x + CHB_OFFSET] >= 198) | 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 | // Build image | ||||
for (int y = 0; y < img->nrow; y++) { | 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; | int skip = 0; | ||||
for (int x = 0; x < width; x++) { | for (int x = 0; x < width; x++) { | ||||
@@ -488,7 +488,7 @@ png_structp rt_png_ptr; | |||||
png_infop rt_info_ptr; | png_infop rt_info_ptr; | ||||
FILE *rt_pngfile; | 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]; | char outName[384]; | ||||
sprintf(outName, "%s/%s-%s.png", opts->path, img->name, chid); | 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){ | void pushRow(float *row, int width){ | ||||
png_byte pix[width]; | |||||
png_byte pix[IMG_WIDTH]; | |||||
for(int i = 0; i < width; i++) | for(int i = 0; i < width; i++) | ||||
pix[i] = row[i]; | pix[i] = row[i]; | ||||
@@ -1,13 +1,13 @@ | |||||
#include "apt.h" | |||||
#include "common.h" | #include "common.h" | ||||
#include "offsets.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 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 pushRow(float *row, int width); | ||||
void closeWriter(); | void closeWriter(); |
@@ -32,94 +32,94 @@ const struct { | |||||
} satcal[] = { | } satcal[] = { | ||||
{ // NOAA 15 | { // NOAA 15 | ||||
{ // PRT coefficient d0, d1, d2 | { // 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 | { // 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 | { // 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 | { // NOAA 16 | ||||
{ // PRT coeff d0, d1, d2 | { // 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 | { // 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 | { // 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 | { // NOAA 17 | ||||
{ // PRT coefficient d0, d1, d2 | { // 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 | { // 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 | { // 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 | { // NOAA 18 | ||||
{ // PRT coefficient d0, d1, d2 | { // 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 | { // 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 | { // 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 | { // NOAA 19 | ||||
{ // PRT coefficient d0, d1, d2 | { // 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 | { // 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 | { // 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; |