You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

main.c 8.9 KiB

21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
19 years ago
21 years ago
21 years ago
21 years ago
19 years ago
21 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
21 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
21 years ago
4 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /*
  2. * This file is part of Aptdec.
  3. * Copyright (c) 2004-2009 Thierry Leconte (F4DWV), Xerbo (xerbo@protonmail.com) 2019-2020
  4. *
  5. * Aptdec is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. *
  18. */
  19. #include <stdlib.h>
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <getopt.h>
  23. #include <libgen.h>
  24. #include <math.h>
  25. #include <sndfile.h>
  26. #include <errno.h>
  27. #include <time.h>
  28. #include "common.h"
  29. #include "offsets.h"
  30. // DSP
  31. extern int init_dsp(double F);
  32. extern int getpixelrow(float *pixelv, int nrow, int *zenith);
  33. // I/O
  34. extern int readRawImage(char *filename, float **prow, int *nrow);
  35. extern int ImageOut(options_t *opts, image_t *img, int offset, int width, char *desc, char *chid, char *palette);
  36. extern int initWriter(options_t *opts, image_t *img, int width, int height, char *desc, char *chid);
  37. extern void pushRow(float *row, int width);
  38. extern void closeWriter();
  39. // Image functions
  40. extern int calibrate(float **prow, int nrow, int offset, int width);
  41. extern void histogramEqualise(float **prow, int nrow, int offset, int width);
  42. extern void linearEnhance(float **prow, int nrow, int offset, int width);
  43. extern void temperature(options_t *opts, image_t *img, int offset, int width);
  44. extern void denoise(float **prow, int nrow, int offset, int width);
  45. extern void distrib(options_t *opts, image_t *img, char *chid);
  46. extern void flipImage(image_t *img, int width, int offset);
  47. // Palettes
  48. extern char GviPalette[256*3];
  49. extern char TempPalette[256*3];
  50. // Row where the satellite is closest to the observer
  51. int zenith = 0;
  52. // Audio file
  53. static SNDFILE *audioFile;
  54. // Function predeclarations
  55. static int initsnd(char *filename);
  56. int getsample(float *sample, int nb);
  57. static int processAudio(char *filename, options_t *opts);
  58. static void usage(void);
  59. int main(int argc, char **argv) {
  60. fprintf(stderr, VERSION"\n");
  61. // Check if there are actually any input files
  62. if(argc == optind || argc == 1){
  63. fprintf(stderr, "No input files provided.\n");
  64. usage();
  65. }
  66. options_t opts = { "r", "", 19, "", ".", 0 };
  67. // Parse arguments
  68. int opt;
  69. while ((opt = getopt(argc, argv, "m:d:i:s:e:r")) != EOF) {
  70. switch (opt) {
  71. case 'd':
  72. opts.path = optarg;
  73. break;
  74. case 'm':
  75. opts.map = optarg;
  76. break;
  77. case 'i':
  78. opts.type = optarg;
  79. break;
  80. case 's':
  81. opts.satnum = atoi(optarg);
  82. if(opts.satnum < 15 || opts.satnum > 19){
  83. fprintf(stderr, "Invalid satellite number, it must be the range 15-19\n");
  84. exit(EPERM);
  85. }
  86. break;
  87. case 'e':
  88. opts.effects = optarg;
  89. break;
  90. case 'r':
  91. opts.realtime = 1;
  92. break;
  93. default:
  94. usage();
  95. }
  96. }
  97. // Process the files
  98. for (; optind < argc; optind++) {
  99. processAudio(argv[optind], &opts);
  100. }
  101. exit(0);
  102. }
  103. static int processAudio(char *filename, options_t *opts){
  104. // Image info struct
  105. image_t img;
  106. // Mapping between wedge value and channel ID
  107. static struct {
  108. char *id[7];
  109. char *name[7];
  110. } ch = {
  111. { "?", "1", "2", "3A", "4", "5", "3B" },
  112. { "unknown", "visble", "near-infrared", "mid-infrared", "thermal-infrared", "thermal-infrared", "mid-infrared" }
  113. };
  114. // Buffer for image channel
  115. char desc[60];
  116. // Parse file path
  117. char path[256], extension[32];
  118. strcpy(path, filename);
  119. strcpy(path, dirname(path));
  120. sscanf(basename(filename), "%[^.].%s", img.name, extension);
  121. // Set output filename to current time when in realtime mode
  122. if(opts->realtime){
  123. time_t t;
  124. time(&t);
  125. strncpy(img.name, ctime(&t), 24);
  126. }
  127. if(opts->realtime) initWriter(opts, &img, IMG_WIDTH, MAX_HEIGHT, "Unprocessed realtime image", "r");
  128. if(strcmp(extension, "png") == 0){
  129. // Read PNG into image buffer
  130. printf("Reading %s", filename);
  131. if(readRawImage(filename, img.prow, &img.nrow) == 0){
  132. fprintf(stderr, "Skipping %s; see above.\n", img.name);
  133. return 0;
  134. }
  135. }else{
  136. // Attempt to open the audio file
  137. if (initsnd(filename) == 0)
  138. exit(EPERM);
  139. // Build image
  140. // TODO: multithreading, would require some sort of input buffer
  141. for (img.nrow = 0; img.nrow < MAX_HEIGHT; img.nrow++) {
  142. // Allocate memory for this row
  143. img.prow[img.nrow] = (float *) malloc(sizeof(float) * 2150);
  144. // Write into memory and break the loop when there are no more samples to read
  145. if (getpixelrow(img.prow[img.nrow], img.nrow, &zenith) == 0)
  146. break;
  147. if(opts->realtime) pushRow(img.prow[img.nrow], IMG_WIDTH);
  148. fprintf(stderr, "Row: %d\r", img.nrow);
  149. fflush(stderr);
  150. }
  151. // Close stream
  152. sf_close(audioFile);
  153. }
  154. if(opts->realtime) closeWriter();
  155. printf("\nTotal rows: %d\n", img.nrow);
  156. // Fallback for detecting the zenith
  157. // TODO: encode zenith in raw images
  158. if(opts->map != NULL && opts->map[0] != '\0' && zenith == 0){
  159. fprintf(stderr, "Guessing zenith in image, map will most likely be misaligned.\n");
  160. zenith = img.nrow / 2;
  161. }
  162. // Calibrate
  163. img.chA = calibrate(img.prow, img.nrow, CHA_OFFSET, CH_WIDTH);
  164. img.chB = calibrate(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH);
  165. printf("Channel A: %s (%s)\n", ch.id[img.chA], ch.name[img.chA]);
  166. printf("Channel B: %s (%s)\n", ch.id[img.chB], ch.name[img.chB]);
  167. // Denoise
  168. if(CONTAINS(opts->effects, 'd')){
  169. denoise(img.prow, img.nrow, CHA_OFFSET, CH_WIDTH);
  170. denoise(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH);
  171. }
  172. // Flip, for southbound passes
  173. if(CONTAINS(opts->effects, 'f')){
  174. flipImage(&img, CH_WIDTH, CHA_OFFSET);
  175. flipImage(&img, CH_WIDTH, CHB_OFFSET);
  176. }
  177. // Temperature
  178. if (CONTAINS(opts->type, 't') && img.chB >= 4) {
  179. temperature(opts, &img, CHB_OFFSET, CH_WIDTH);
  180. ImageOut(opts, &img, CHB_OFFSET, CH_WIDTH, "Temperature", "t", (char *)TempPalette);
  181. }
  182. // MCIR
  183. if (CONTAINS(opts->type, 'm'))
  184. ImageOut(opts, &img, 0, IMG_WIDTH, "MCIR", "m", NULL);
  185. // Linear equalise
  186. if(CONTAINS(opts->effects, 'l')){
  187. linearEnhance(img.prow, img.nrow, CHA_OFFSET, CH_WIDTH);
  188. linearEnhance(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH);
  189. }
  190. // Histogram equalise
  191. if(CONTAINS(opts->effects, 'h')){
  192. histogramEqualise(img.prow, img.nrow, CHA_OFFSET, CH_WIDTH);
  193. histogramEqualise(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH);
  194. }
  195. // False color
  196. if(CONTAINS(opts->type, 'c')){
  197. if(img.chA == 2 && img.chB >= 4){
  198. ImageOut(opts, &img, 0, CH_WIDTH, "False Color", "c", NULL);
  199. }else{
  200. fprintf(stderr, "Lacking channels required for false color computation\n");
  201. }
  202. }
  203. // Raw image
  204. if (CONTAINS(opts->type, 'r')) {
  205. sprintf(desc, "%s (%s) & %s (%s)", ch.id[img.chA], ch.name[img.chA], ch.id[img.chB], ch.name[img.chB]);
  206. ImageOut(opts, &img, 0, IMG_WIDTH, desc, "r", NULL);
  207. }
  208. // Channel A
  209. if (CONTAINS(opts->type, 'a')) {
  210. sprintf(desc, "%s (%s)", ch.id[img.chA], ch.name[img.chA]);
  211. ImageOut(opts, &img, CHA_OFFSET, CH_WIDTH, desc, ch.id[img.chA], NULL);
  212. }
  213. // Channel B
  214. if (CONTAINS(opts->type, 'b')) {
  215. sprintf(desc, "%s (%s)", ch.id[img.chB], ch.name[img.chB]);
  216. ImageOut(opts, &img, CHB_OFFSET, CH_WIDTH, desc, ch.id[img.chB], NULL);
  217. }
  218. // Distribution image
  219. if (CONTAINS(opts->type, 'd'))
  220. distrib(opts, &img, "d");
  221. return 1;
  222. }
  223. static int initsnd(char *filename) {
  224. SF_INFO infwav;
  225. int res;
  226. // Open audio file
  227. infwav.format = 0;
  228. audioFile = sf_open(filename, SFM_READ, &infwav);
  229. if (audioFile == NULL) {
  230. fprintf(stderr, "Could not open %s for reading\n", filename);
  231. return 0;
  232. }
  233. res = init_dsp(infwav.samplerate);
  234. printf("Input file: %s\n", filename);
  235. if(res < 0) {
  236. fprintf(stderr, "Input sample rate too low: %d\n", infwav.samplerate);
  237. return 0;
  238. }else if(res > 0) {
  239. fprintf(stderr, "Input sample rate too high: %d\n", infwav.samplerate);
  240. return 0;
  241. }
  242. printf("Input sample rate: %d\n", infwav.samplerate);
  243. // TODO: accept stereo audio
  244. if (infwav.channels != 1) {
  245. fprintf(stderr, "Too many channels in input file: %d\n", infwav.channels);
  246. return 0;
  247. }
  248. return 1;
  249. }
  250. // Read samples from the wave file
  251. int getsample(float *sample, int nb) {
  252. return sf_read_float(audioFile, sample, nb);
  253. }
  254. static void usage(void) {
  255. fprintf(stderr,
  256. "Aptdec [options] audio files ...\n"
  257. "Options:\n"
  258. " -e [t|h|d|p|f|l] Effects\n"
  259. " t: Crop telemetry\n"
  260. " h: Histogram equalise\n"
  261. " d: Denoise\n"
  262. " p: Precipitation\n"
  263. " f: Flip image\n"
  264. " l: Linear equalise\n"
  265. " -i [r|a|b|c|t|m] Output image\n"
  266. " r: Raw\n"
  267. " a: Channel A\n"
  268. " b: Channel B\n"
  269. " c: False color\n"
  270. " t: Temperature\n"
  271. " m: MCIR\n"
  272. " -d <dir> Image destination directory.\n"
  273. " -s [15-19] Satellite number\n"
  274. " -m <file> Map file\n"
  275. " -r Realtime decode\n"
  276. "\nRefer to the README for more infomation\n");
  277. exit(EINVAL);
  278. }