75 {
76 const char* opt_fsk_id = NULL;
77 const char* opt_channels = "1";
78 const char* opt_mode = "M1";
79 const char* opt_input_img = NULL;
80 const char* opt_output_au = NULL;
81 char* endptr = NULL;
82 int opt_bits = 16;
83 int opt_rate = 48000;
84 int opt_idx = 0;
85 uint8_t total_audio_channels;
86 uint8_t select_audio_channels;
88
89 static struct option long_options[] = {
90 {.name = "bits",
91 .has_arg = required_argument,
92 .flag = NULL,
93 .val = 'B'},
94 {.name = "chan",
95 .has_arg = required_argument,
96 .flag = NULL,
97 .val = 'C'},
98 {.name = "mode",
99 .has_arg = required_argument,
100 .flag = NULL,
101 .val = 'M'},
102 {.name = "rate",
103 .has_arg = required_argument,
104 .flag = NULL,
105 .val = 'R'},
106 {.name = "fsk-id",
107 .has_arg = required_argument,
108 .flag = NULL,
109 .val = 'f'},
110 {.name = NULL, .has_arg = 0, .flag = NULL, .val = 0},
111 };
112
113 while (1) {
114 int c = getopt_long(argc, argv, "B:C:M:R:f:", long_options,
115 &opt_idx);
116 if (c == -1) {
117 break;
118 } else if (!c && !long_options[opt_idx].flag) {
119 c = long_options[opt_idx].val;
120 }
121
122 switch (c) {
123 case 0:
124 break;
125 case 'B':
126 opt_bits = strtol(optarg, &endptr, 10);
127 switch (opt_bits) {
128 case 8:
129
131 break;
132 case 16:
133
135 break;
136 case 32:
137 switch (endptr[0]) {
138 case 0:
139 case 'S':
140 case 's':
141
142 audio_encoding
144 break;
145 case 'f':
146 case 'F':
147
148 audio_encoding
150 break;
151 }
152 break;
153 case 64:
154
156 break;
157 default:
158 fprintf(stderr,
159 "Invalid number of bits: %s\n"
160 "Supported values: 8, 16, 32/32s/32f "
161 "and 64\n",
162 optarg);
163 return (1);
164 }
165 break;
166 case 'C':
167 opt_channels = optarg;
168 break;
169 case 'M':
170 opt_mode = optarg;
171 break;
172 case 'R':
173 opt_rate = atoi(optarg);
174 break;
175 case 'f':
176 opt_fsk_id = optarg;
177 break;
178 default:
180 return 1;
181 }
182 }
183
184 if ((argc - optind) != 2) {
186 return 1;
187 }
188 opt_input_img = argv[optind];
189 opt_output_au = argv[optind + 1];
190
191 switch (opt_channels[0]) {
192 case '1':
193 case 'm':
194 case 'M':
195
196 total_audio_channels = 1;
197 select_audio_channels = 1;
198 break;
199 case '2':
200 case 's':
201 case 'S':
202
203 total_audio_channels = 2;
204 select_audio_channels = UINT8_MAX;
205 break;
206 case 'l':
207 case 'L':
208
209 total_audio_channels = 2;
210 select_audio_channels = 1;
211 break;
212 case 'r':
213 case 'R':
214
215 total_audio_channels = 2;
216 select_audio_channels = 2;
217 break;
218 default:
219 printf("Unknown channel mode: %s\n", opt_channels);
220 return (1);
221 }
222
226
227 if (!mode) {
228 fprintf(stderr, "Unknown mode %s\n", opt_mode);
229 printf("Valid modes are:\n");
231 return 1;
232 }
233
234 uint16_t colourspace
236 uint8_t colours = 3;
238 colours = 1;
239 }
240
241 uint8_t* fb
242 = malloc(mode->
width * mode->
height * colours *
sizeof(uint8_t));
243
244 FILE* in = fopen(opt_input_img, "rb");
245 if (!in) {
246 perror("Failed to open input file");
247 return 1;
248 }
249 gdImagePtr im = gdImageCreateFromPng(in);
250 fclose(in);
251
252
253 gdImagePtr im_resized = gdImageScale(im, mode->
width, mode->
height);
254
255 for (uint16_t y = 0; y < mode->
height; y++) {
256 for (uint16_t x = 0; x < mode->
width; x++) {
257 int c = gdImageGetTrueColorPixel(im_resized, x, y);
259 uint8_t pv[colours];
260 uint8_t r = gdTrueColorGetRed(c);
261 uint8_t g = gdTrueColorGetGreen(c);
262 uint8_t b = gdTrueColorGetBlue(c);
263
264 switch (colourspace) {
267 break;
269 pv[0] = r;
270 pv[1] = g;
271 pv[2] = b;
272 break;
278 break;
279 }
280 default:
281 break;
282 }
283
284 for (uint8_t c = 0; c < colours; c++) {
285 fb[idx + c] = pv[c];
286 }
287 }
288 }
289 gdImageDestroy(im_resized);
290 gdImageDestroy(im);
291
294 {
296 &au, opt_output_au, mod.osc.sample_rate, audio_encoding,
297 total_audio_channels);
298 if (res < 0) {
299 fprintf(stderr, "Failed to open output file %s: %s\n",
300 opt_output_au, strerror(-res));
301 }
302 }
303
304
305
306
308
309
310
311 double samples[total_audio_channels];
312
314
315
316 for (uint8_t ch = 0; ch < total_audio_channels; ch++) {
317 if (select_audio_channels & (1 << ch)) {
318 samples[ch] = mod.osc.output;
319 } else {
320 samples[ch] = 0.0;
321 }
322 }
323
324
326 &au, total_audio_channels, samples);
327 if (au_res < 0) {
328 fprintf(stderr, "Failed to write audio samples: %s\n",
329 strerror(-au_res));
330 return (2);
331 }
332 }
333
334 {
336 if (au_res < 0) {
337 fprintf(stderr,
338 "Failed to close audio output file: %s\n",
339 strerror(-au_res));
340 return (2);
341 }
342 }
343
344 return 0;
345}
#define SSTVENC_CSO_MODE_YUV
#define SSTVENC_CSO_MODE_RGB
#define SSTVENC_CSO_MODE_MONO
#define SSTVENC_CSO_MODE_YUV2
#define SSTVENC_CSO_MASK_MODE
void sstvenc_modulator_init(struct sstvenc_mod *const mod, const struct sstvenc_mode *mode, const char *fsk_id, const uint8_t *framebuffer, double rise_time, double fall_time, uint32_t sample_rate, uint8_t time_unit)
void sstvenc_modulator_compute(struct sstvenc_mod *const mod)
#define SSTVENC_ENCODER_PHASE_DONE
uint8_t sstvenc_yuv_calc_v(uint8_t r, uint8_t g, uint8_t b)
uint8_t sstvenc_yuv_calc_y(uint8_t r, uint8_t g, uint8_t b)
uint8_t sstvenc_yuv_calc_u(uint8_t r, uint8_t g, uint8_t b)
uint16_t colour_space_order
const struct sstvenc_mode * sstvenc_get_mode_by_name(const char *name)
uint32_t sstvenc_get_pixel_posn(const struct sstvenc_mode *const mode, uint16_t x, uint16_t y)
int sstvenc_sunau_enc_write(struct sstvenc_sunau *const enc, size_t n_samples, const double *samples)
int sstvenc_sunau_enc_init(struct sstvenc_sunau *const enc, const char *path, uint32_t sample_rate, uint8_t encoding, uint8_t channels)
int sstvenc_sunau_enc_close(struct sstvenc_sunau *const enc)
#define SSTVENC_TS_UNIT_MILLISECONDS
static void show_modes(void)
static void show_usage(const char *prog_name)