libsstvenc
Asynchronous Analogue SSTV encoder
Loading...
Searching...
No Matches
morse.c File Reference
#include <getopt.h>
#include <libsstvenc/cw.h>
#include <libsstvenc/sunau.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Include dependency graph for morse.c:

Go to the source code of this file.

Functions

static void show_usage (const char *prog_name)
 
int main (int argc, char *argv[])
 

Function Documentation

◆ main()

int main ( int argc,
char * argv[] )

Definition at line 41 of file morse.c.

41 {
42 const char* opt_channels = "1";
43 const char* opt_input_txt = NULL;
44 const char* opt_output_au = NULL;
45 char* endptr = NULL;
46 int opt_bits = 16;
47 int opt_rate = 48000;
48 int opt_idx = 0;
49 double opt_freq = 800.0;
50 double opt_dit_period = 80.0;
51 double opt_slope_period = -1.0;
52 uint8_t total_audio_channels;
53 uint8_t select_audio_channels;
54 uint8_t audio_encoding = SSTVENC_SUNAU_FMT_S16;
55
56 static struct option long_options[] = {
57 {.name = "bits",
58 .has_arg = required_argument,
59 .flag = NULL,
60 .val = 'B'},
61 {.name = "chan",
62 .has_arg = required_argument,
63 .flag = NULL,
64 .val = 'C'},
65 {.name = "rate",
66 .has_arg = required_argument,
67 .flag = NULL,
68 .val = 'R'},
69 {.name = "slope",
70 .has_arg = required_argument,
71 .flag = NULL,
72 .val = 'S'},
73 {.name = "dit-period",
74 .has_arg = required_argument,
75 .flag = NULL,
76 .val = 'd'},
77 {.name = "freq",
78 .has_arg = required_argument,
79 .flag = NULL,
80 .val = 'f'},
81 {.name = NULL, .has_arg = 0, .flag = NULL, .val = 0},
82 };
83
84 while (1) {
85 int c = getopt_long(argc, argv, "B:C:R:S:d:f:", long_options,
86 &opt_idx);
87 if (c == -1) {
88 break;
89 } else if (!c && !long_options[opt_idx].flag) {
90 c = long_options[opt_idx].val;
91 }
92
93 switch (c) {
94 case 0:
95 break;
96 case 'B': /* Set bits */
97 opt_bits = strtol(optarg, &endptr, 10);
98 switch (opt_bits) {
99 case 8:
100 /* 8-bit signed */
101 audio_encoding = SSTVENC_SUNAU_FMT_S8;
102 break;
103 case 16:
104 /* 16-bit signed */
105 audio_encoding = SSTVENC_SUNAU_FMT_S16;
106 break;
107 case 32:
108 switch (endptr[0]) {
109 case 0:
110 case 'S':
111 case 's':
112 /* 32-bit signed */
113 audio_encoding
115 break;
116 case 'f':
117 case 'F':
118 /* 32-bit float */
119 audio_encoding
121 break;
122 }
123 break;
124 case 64:
125 /* 64-bit float */
126 audio_encoding = SSTVENC_SUNAU_FMT_F64;
127 break;
128 default:
129 fprintf(stderr,
130 "Invalid number of bits: %s\n"
131 "Supported values: 8, 16, 32/32s/32f "
132 "and 64\n",
133 optarg);
134 return (1);
135 }
136 break;
137 case 'C': /* Set channel count / usage */
138 opt_channels = optarg;
139 break;
140 case 'R': /* Set sample rate */
141 opt_rate = atoi(optarg);
142 break;
143 case 'S': /* Set slope period */
144 opt_slope_period = strtod(optarg, &endptr);
145 if (endptr[0]) {
146 fprintf(stderr, "Invalid slope period: %s\n",
147 optarg);
148 return (1);
149 }
150 break;
151 case 'd': /* Set dit period */
152 opt_dit_period = strtod(optarg, &endptr);
153 if (endptr[0]) {
154 fprintf(stderr, "Invalid dit period: %s\n",
155 optarg);
156 return (1);
157 }
158 break;
159 case 'f': /* Set frequency */
160 opt_freq = strtod(optarg, &endptr);
161 if (endptr[0]) {
162 fprintf(stderr, "Invalid frequency: %s\n",
163 optarg);
164 return (1);
165 }
166 break;
167 default:
168 show_usage(argv[0]);
169 return 1;
170 }
171 }
172
173 if ((argc - optind) != 2) {
174 show_usage(argv[0]);
175 return 1;
176 }
177 opt_input_txt = argv[optind];
178 opt_output_au = argv[optind + 1];
179
180 switch (opt_channels[0]) {
181 case '1':
182 case 'm':
183 case 'M':
184 /* Mono output */
185 total_audio_channels = 1;
186 select_audio_channels = 1;
187 break;
188 case '2':
189 case 's':
190 case 'S':
191 /* Stereo output : both channels */
192 total_audio_channels = 2;
193 select_audio_channels = UINT8_MAX;
194 break;
195 case 'l':
196 case 'L':
197 /* Stereo output : left channel */
198 total_audio_channels = 2;
199 select_audio_channels = 1;
200 break;
201 case 'r':
202 case 'R':
203 /* Stereo output : left channel */
204 total_audio_channels = 2;
205 select_audio_channels = 2;
206 break;
207 default:
208 printf("Unknown channel mode: %s\n", opt_channels);
209 return (1);
210 }
211
212 if (opt_slope_period < 0) {
213 opt_slope_period = 0.2 * opt_dit_period;
214 }
215
216 struct sstvenc_cw_mod cw;
217 struct sstvenc_sunau au;
218
219 sstvenc_cw_init(&cw, opt_input_txt, 1.0, opt_freq, opt_dit_period,
220 opt_slope_period, opt_rate,
222 {
223 int res = sstvenc_sunau_enc_init(&au, opt_output_au, opt_rate,
224 audio_encoding,
225 total_audio_channels);
226 if (res < 0) {
227 fprintf(stderr, "Failed to open output file %s: %s\n",
228 opt_output_au, strerror(-res));
229 }
230 }
231
232 while (cw.state != SSTVENC_CW_MOD_STATE_DONE) {
233 /* Our audio samples for this audio frame */
234 double samples[total_audio_channels];
235
236 /* Compute the next CW sample. */
238
239 /* Fill the frame */
240 for (uint8_t ch = 0; ch < total_audio_channels; ch++) {
241 if (select_audio_channels & (1 << ch)) {
242 samples[ch] = cw.output;
243 } else {
244 samples[ch] = 0.0;
245 }
246 }
247
248 /* Write the audio frame */
249 int au_res = sstvenc_sunau_enc_write(
250 &au, total_audio_channels, samples);
251 if (au_res < 0) {
252 fprintf(stderr, "Failed to write audio samples: %s\n",
253 strerror(-au_res));
254 return (2);
255 }
256 }
257
258 {
259 int au_res = sstvenc_sunau_enc_close(&au);
260 if (au_res < 0) {
261 fprintf(stderr,
262 "Failed to close audio output file: %s\n",
263 strerror(-au_res));
264 return (2);
265 }
266 }
267
268 return 0;
269}
#define SSTVENC_CW_MOD_STATE_DONE
Definition cw.h:91
void sstvenc_cw_compute(struct sstvenc_cw_mod *const cw)
Definition cw.c:507
void sstvenc_cw_init(struct sstvenc_cw_mod *const cw, const char *text, double amplitude, double frequency, double dit_period, double slope_period, uint32_t sample_rate, uint8_t time_unit)
Definition cw.c:312
#define SSTVENC_SUNAU_FMT_F64
Definition sunau.h:35
#define SSTVENC_SUNAU_FMT_F32
Definition sunau.h:34
#define SSTVENC_SUNAU_FMT_S16
Definition sunau.h:32
#define SSTVENC_SUNAU_FMT_S32
Definition sunau.h:33
#define SSTVENC_SUNAU_FMT_S8
Definition sunau.h:31
int sstvenc_sunau_enc_write(struct sstvenc_sunau *const enc, size_t n_samples, const double *samples)
Definition sunau.c:310
int sstvenc_sunau_enc_init(struct sstvenc_sunau *const enc, const char *path, uint32_t sample_rate, uint8_t encoding, uint8_t channels)
Definition sunau.c:288
int sstvenc_sunau_enc_close(struct sstvenc_sunau *const enc)
Definition sunau.c:340
#define SSTVENC_TS_UNIT_MILLISECONDS
Definition timescale.h:37
static void show_usage(const char *prog_name)
Definition morse.c:13

References sstvenc_cw_mod::output, show_usage(), sstvenc_cw_compute(), sstvenc_cw_init(), SSTVENC_CW_MOD_STATE_DONE, sstvenc_sunau_enc_close(), sstvenc_sunau_enc_init(), sstvenc_sunau_enc_write(), SSTVENC_SUNAU_FMT_F32, SSTVENC_SUNAU_FMT_F64, SSTVENC_SUNAU_FMT_S16, SSTVENC_SUNAU_FMT_S32, SSTVENC_SUNAU_FMT_S8, SSTVENC_TS_UNIT_MILLISECONDS, and sstvenc_cw_mod::state.

Here is the call graph for this function:

◆ show_usage()

static void show_usage ( const char * prog_name)
static

Definition at line 13 of file morse.c.

13 {
14 printf("Usage: %s [options] \"MORSE CODE TEXT\" output.au\n"
15 "Options:\n"
16 " {--bits | -B} BITS: set the number of bits per sample\n"
17 " 8: 8-bit signed integer\n"
18 " 16: 16-bit signed integer (default)\n"
19 " 32: 32-bit signed integer\n"
20 " 32s: also 32-bit signed integer (alias)\n"
21 " 32f: 32-bit IEEE-754 float\n"
22 " 64: 64-bit IEEE-754 float\n"
23 " {--chan | -C} CHAN: select audio channels\n"
24 " 1: mono output (default)\n"
25 " m: mono output (alias)\n"
26 " 2: stereo output -- use both channels\n"
27 " s: stereo output (alias) -- use both channels\n"
28 " l: stereo output -- use left channel\n"
29 " r: stereo output -- use right channel\n"
30 " {--rate | -R} RATE: sample rate in Hz\n"
31 " {--slope | -S} SLOPE: slope period in milliseconds "
32 "(negative for "
33 "auto)\n"
34 " {--dit-period | -d} PERIOD: Set the morse code dit period "
35 "in milliseconds\n"
36 " {--freq | -f} FREQ: Set the morse code oscillator "
37 "frequency\n",
38 prog_name);
39}

Referenced by main().

Here is the caller graph for this function: