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 9.0 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
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
21 years ago
4 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  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 "offsets.h"
  29. // DSP
  30. extern int init_dsp(double F);
  31. extern int getpixelrow(float *pixelv, int nrow, int *zenith, int reset);
  32. #include "pngio.h"
  33. #include "image.h"
  34. #include "color.h"
  35. // Audio file
  36. static SNDFILE *audioFile;
  37. // Number of channels in audio file
  38. int channels = 1;
  39. // Function declarations
  40. static int initsnd(char *filename);
  41. int getsample(float *sample, int nb);
  42. static int processAudio(char *filename, options_t *opts);
  43. static void usage(void);
  44. int main(int argc, char **argv) {
  45. fprintf(stderr, VERSION"\n");
  46. // Check if there are actually any input files
  47. if(argc == optind || argc == 1){
  48. fprintf(stderr, "No input files provided.\n");
  49. usage();
  50. }
  51. options_t opts = { "r", "", 19, "", ".", 0, "", "", 1.0, 0 };
  52. // Parse arguments
  53. int opt;
  54. while ((opt = getopt(argc, argv, "o:m:d:i:s:e:p:g:k:r")) != EOF) {
  55. switch (opt) {
  56. case 'd':
  57. opts.path = optarg;
  58. break;
  59. case 'm':
  60. opts.map = optarg;
  61. break;
  62. case 'i':
  63. opts.type = optarg;
  64. break;
  65. case 's':
  66. opts.satnum = atoi(optarg);
  67. if(opts.satnum < 15 || opts.satnum > 19){
  68. fprintf(stderr, "Invalid satellite number, it must be the range 15-19\n");
  69. exit(EPERM);
  70. }
  71. break;
  72. case 'e':
  73. opts.effects = optarg;
  74. break;
  75. case 'r':
  76. opts.realtime = 1;
  77. break;
  78. case 'o':
  79. opts.filename = optarg;
  80. break;
  81. case 'p':
  82. opts.palette = optarg;
  83. break;
  84. case 'g':
  85. opts.gamma = atof(optarg);
  86. break;
  87. case 'k':
  88. opts.mapOffset = atoi(optarg);
  89. break;
  90. default:
  91. usage();
  92. }
  93. }
  94. // Process the files
  95. for (; optind < argc; optind++) {
  96. processAudio(argv[optind], &opts);
  97. }
  98. exit(0);
  99. }
  100. static int processAudio(char *filename, options_t *opts){
  101. // Image info struct
  102. image_t img;
  103. // Mapping between wedge value and channel ID
  104. static struct {
  105. char *id[7];
  106. char *name[7];
  107. } ch = {
  108. { "?", "1", "2", "3A", "4", "5", "3B" },
  109. { "unknown", "visble", "near-infrared", "mid-infrared", "thermal-infrared", "thermal-infrared", "mid-infrared" }
  110. };
  111. // Buffer for image channel
  112. char desc[60];
  113. // Parse file path
  114. char path[256], extension[32];
  115. strcpy(path, filename);
  116. strcpy(path, dirname(path));
  117. sscanf(basename(filename), "%255[^.].%31s", img.name, extension);
  118. if(opts->realtime){
  119. // Set output filename to current time when in realtime mode
  120. time_t t;
  121. time(&t);
  122. strncpy(img.name, ctime(&t), 24);
  123. // Init a row writer
  124. initWriter(opts, &img, IMG_WIDTH, MAX_HEIGHT, "Unprocessed realtime image", "r");
  125. }
  126. if(strcmp(extension, "png") == 0){
  127. // Read PNG into image buffer
  128. printf("Reading %s\n", filename);
  129. if(readRawImage(filename, img.prow, &img.nrow) == 0){
  130. exit(EPERM);
  131. }
  132. }else{
  133. // Attempt to open the audio file
  134. if (initsnd(filename) == 0)
  135. exit(EPERM);
  136. // Build image
  137. // TODO: multithreading, would require some sort of input buffer
  138. for (img.nrow = 0; img.nrow < MAX_HEIGHT; img.nrow++) {
  139. // Allocate memory for this row
  140. img.prow[img.nrow] = (float *) malloc(sizeof(float) * 2150);
  141. // Write into memory and break the loop when there are no more samples to read
  142. if (getpixelrow(img.prow[img.nrow], img.nrow, &img.zenith, (img.nrow == 0)) == 0)
  143. break;
  144. if(opts->realtime) pushRow(img.prow[img.nrow], IMG_WIDTH);
  145. fprintf(stderr, "Row: %d\r", img.nrow);
  146. fflush(stderr);
  147. }
  148. // Close stream
  149. sf_close(audioFile);
  150. }
  151. if(opts->realtime) closeWriter();
  152. printf("Total rows: %d\n", img.nrow);
  153. // Fallback for detecting the zenith
  154. // TODO: encode metadata in raw images
  155. if(opts->map != NULL && opts->map[0] != '\0' && img.zenith == 0){
  156. fprintf(stderr, "Guessing zenith in image, map will most likely be misaligned.\n");
  157. img.zenith = img.nrow / 2;
  158. }
  159. // Calibrate
  160. img.chA = calibrate(img.prow, img.nrow, CHA_OFFSET, CH_WIDTH);
  161. img.chB = calibrate(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH);
  162. printf("Channel A: %s (%s)\n", ch.id[img.chA], ch.name[img.chA]);
  163. printf("Channel B: %s (%s)\n", ch.id[img.chB], ch.name[img.chB]);
  164. // Crop noise from start and end of image
  165. if(CONTAINS(opts->effects, Crop_Noise)){
  166. cropNoise(&img);
  167. }
  168. // Denoise
  169. if(CONTAINS(opts->effects, Denoise)){
  170. denoise(img.prow, img.nrow, CHA_OFFSET, CH_WIDTH);
  171. denoise(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH);
  172. }
  173. // Flip, for northbound passes
  174. if(CONTAINS(opts->effects, Flip_Image)){
  175. flipImage(&img, CH_WIDTH, CHA_OFFSET);
  176. flipImage(&img, CH_WIDTH, CHB_OFFSET);
  177. }
  178. // Temperature
  179. if (CONTAINS(opts->type, Temperature) && img.chB >= 4) {
  180. // Create another buffer as to not modify the orignal
  181. image_t tmpimg = img;
  182. for(int i = 0; i < img.nrow; i++){
  183. tmpimg.prow[i] = (float *) malloc(sizeof(float) * 2150);
  184. memcpy(tmpimg.prow[i], img.prow[i], sizeof(float) * 2150);
  185. }
  186. // Perform temperature calibration
  187. temperature(opts, &tmpimg, CHB_OFFSET, CH_WIDTH);
  188. ImageOut(opts, &tmpimg, CHB_OFFSET, CH_WIDTH, "Temperature", Temperature, (char *)TempPalette);
  189. }
  190. // MCIR
  191. if (CONTAINS(opts->type, MCIR))
  192. ImageOut(opts, &img, CHA_OFFSET, CH_WIDTH, "MCIR", MCIR, NULL);
  193. // Linear equalise
  194. if(CONTAINS(opts->effects, Linear_Equalise)){
  195. linearEnhance(img.prow, img.nrow, CHA_OFFSET, CH_WIDTH);
  196. linearEnhance(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH);
  197. }
  198. // Histogram equalise
  199. if(CONTAINS(opts->effects, Histogram_Equalise)){
  200. histogramEqualise(img.prow, img.nrow, CHA_OFFSET, CH_WIDTH);
  201. histogramEqualise(img.prow, img.nrow, CHB_OFFSET, CH_WIDTH);
  202. }
  203. // Raw image
  204. if (CONTAINS(opts->type, Raw_Image)) {
  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, Raw_Image, NULL);
  207. }
  208. // Palette image
  209. if (CONTAINS(opts->type, Palleted)) {
  210. img.palette = opts->palette;
  211. strcpy(desc, "Palette composite");
  212. ImageOut(opts, &img, CHA_OFFSET, 909, desc, Palleted, NULL);
  213. }
  214. // Channel A
  215. if (CONTAINS(opts->type, Channel_A)) {
  216. sprintf(desc, "%s (%s)", ch.id[img.chA], ch.name[img.chA]);
  217. ImageOut(opts, &img, CHA_OFFSET, CH_WIDTH, desc, Channel_A, NULL);
  218. }
  219. // Channel B
  220. if (CONTAINS(opts->type, Channel_B)) {
  221. sprintf(desc, "%s (%s)", ch.id[img.chB], ch.name[img.chB]);
  222. ImageOut(opts, &img, CHB_OFFSET, CH_WIDTH, desc, Channel_B, NULL);
  223. }
  224. return 1;
  225. }
  226. static int initsnd(char *filename) {
  227. SF_INFO infwav;
  228. int res;
  229. // Open audio file
  230. infwav.format = 0;
  231. audioFile = sf_open(filename, SFM_READ, &infwav);
  232. if (audioFile == NULL) {
  233. fprintf(stderr, "Could not open %s\n", filename);
  234. return 0;
  235. }
  236. res = init_dsp(infwav.samplerate);
  237. printf("Input file: %s\n", filename);
  238. if(res < 0) {
  239. fprintf(stderr, "Input sample rate too low: %d\n", infwav.samplerate);
  240. return 0;
  241. }else if(res > 0) {
  242. fprintf(stderr, "Input sample rate too high: %d\n", infwav.samplerate);
  243. return 0;
  244. }
  245. printf("Input sample rate: %d\n", infwav.samplerate);
  246. channels = infwav.channels;
  247. return 1;
  248. }
  249. // Read samples from the audio file
  250. int getsample(float *sample, int nb) {
  251. if(channels == 1){
  252. return sf_read_float(audioFile, sample, nb);
  253. }else{
  254. /* Multi channel audio is encoded such as:
  255. * Ch1,Ch2,Ch1,Ch2,Ch1,Ch2
  256. */
  257. float buf[nb * channels]; // Something like BLKIN*2 could also be used
  258. int samples = sf_read_float(audioFile, buf, nb * channels);
  259. for(int i = 0; i < nb; i++) sample[i] = buf[i * channels];
  260. return samples / channels;
  261. }
  262. }
  263. static void usage(void) {
  264. fprintf(stderr,
  265. "Aptdec [options] audio files ...\n"
  266. "Options:\n"
  267. " -i [r|a|b|t|m|p] Output image\n"
  268. " r: Raw\n"
  269. " a: Channel A\n"
  270. " b: Channel B\n"
  271. " t: Temperature\n"
  272. " m: MCIR\n"
  273. " p: Paletted image\n"
  274. " -e [t|h|d|p|f|l] Effects\n"
  275. " t: Crop telemetry\n"
  276. " h: Histogram equalise\n"
  277. " d: Denoise\n"
  278. " p: Precipitation\n"
  279. " f: Flip image\n"
  280. " l: Linear equalise\n"
  281. " c: Crop noise\n"
  282. " -o <path> Output filename\n"
  283. " -d <path> Image destination directory.\n"
  284. " -s [15-19] Satellite number\n"
  285. " -m <path> Map file\n"
  286. " -p <path> Path to palette\n"
  287. " -r Realtime decode\n"
  288. " -g Gamma adjustment (1.0 = off)\n"
  289. " -k Map offset (in px, default: 0)"
  290. "\nRefer to the README for more infomation\n");
  291. exit(EINVAL);
  292. }