Commit | Line | Data |
---|---|---|
13b093b1 MW |
1 | .\" -*-nroff-*- |
2 | .\" | |
3 | .\" Manual for the audio conversion gremlin | |
4 | .\" | |
5 | .\" (c) 2016 Mark Wooding | |
6 | .\" | |
7 | . | |
8 | .\"----- Licensing notice --------------------------------------------------- | |
9 | .\" | |
10 | .\" This file is part of the `autoys' audio tools collection. | |
11 | .\" | |
12 | .\" `autoys' is free software; you can redistribute it and/or modify | |
13 | .\" it under the terms of the GNU General Public License as published by | |
14 | .\" the Free Software Foundation; either version 2 of the License, or | |
15 | .\" (at your option) any later version. | |
16 | .\" | |
17 | .\" `autoys' is distributed in the hope that it will be useful, | |
18 | .\" but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | .\" GNU General Public License for more details. | |
21 | .\" | |
22 | .\" You should have received a copy of the GNU General Public License | |
23 | .\" along with `autoys'; if not, write to the Free Software Foundation, | |
24 | .\" Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
25 | . | |
26 | .TH gremlin 1 "13 February 2016" "Mark Wooding" "autoys" | |
27 | . | |
28 | .\"-------------------------------------------------------------------------- | |
29 | .SH NAME | |
30 | gremlin \- batch audio file converter | |
31 | . | |
32 | .SH SYNOPSIS | |
33 | .B gremlin | |
34 | .RB [ \-in ] | |
35 | .RB [ \-T | |
36 | .IR timeout ] | |
37 | .RB [ \-t | |
38 | .IR timeout ] | |
39 | .I config | |
40 | . | |
41 | .\"-------------------------------------------------------------------------- | |
42 | .SH DESCRIPTION | |
43 | . | |
44 | The | |
45 | .B gremlin | |
46 | program converts audio files | |
47 | in an input `master' directory tree, | |
48 | which presumably contains | |
49 | high-quality (ideally lossless) encodings | |
50 | of interesting audio, | |
51 | writing corresponding converted files | |
52 | to a collection of output directory trees. | |
53 | It's non-interactive, idempotent, and restartable; | |
54 | it never modifies its master tree. | |
55 | It's exactly the sort of thing you want to | |
56 | install as a daily cron job. | |
57 | .PP | |
58 | The | |
59 | .B gremlin | |
60 | reads a configuration file | |
61 | which describes the conversion policy for each of the output trees. | |
62 | The policy can say things like: | |
63 | copy MP3 files up to 160kb/s, | |
64 | or Ogg Vorbis files up to 128kb/s; | |
65 | and convert everything else to 128kb/s Ogg Vorbis. | |
66 | .PP | |
67 | The | |
68 | .B gremlin | |
69 | can also convert image files, such as cover art. | |
70 | .PP | |
71 | Input files can be anything which | |
72 | GStreamer and/or the Python Imaging Library can understand; | |
73 | output files are more constrained, | |
74 | because the | |
75 | .B gremlin | |
76 | has to be able to understand | |
77 | their relevant properties. | |
78 | The currently supported audio formats are | |
79 | Ogg Vorbis and | |
80 | MP3; | |
81 | image formats are | |
82 | JPEG, | |
83 | PNG, and | |
84 | BMP. | |
85 | .PP | |
86 | In a little more detail: | |
87 | the | |
88 | .B gremlin | |
89 | works through its input master tree, | |
90 | one directory at a time. | |
91 | For each master directory, | |
92 | it tries to write a converted version | |
93 | to a corresponding output directory | |
94 | in each of the output trees. | |
95 | For each file in the master directory, | |
96 | it determines which files should be made | |
97 | in each output directory: | |
98 | if those files exist, | |
99 | and are not older than the master file, | |
100 | then they're left alone on the assumption that they're up-to-date; | |
101 | otherwise, the | |
102 | .B gremlin | |
103 | will make the output files by converting the master file. | |
104 | .PP | |
105 | Any other files or directories in the output directory | |
106 | will be | |
107 | .IR deleted . | |
108 | The | |
109 | .B gremlin | |
110 | assumes that its output trees belong entirely to it, | |
111 | to maintain according to its configuration, | |
112 | and that unexpected files are either | |
113 | debris left over from an earlier failure | |
114 | or a result of a policy change, | |
115 | and in either case the right thing to do is | |
116 | to delete the offending files. | |
117 | . | |
118 | .SS "Command line syntax" | |
119 | The following options are recognized. | |
120 | .TP | |
121 | .B "\-h, \-\-help" | |
122 | Write a help message to standard output | |
123 | describing the | |
124 | .BR gremlin 's | |
125 | command-line options, | |
126 | and exit with status zero. | |
127 | .TP | |
128 | .B "\-\-version" | |
129 | Write the | |
130 | .BR gremlin 's | |
131 | version number to standard output | |
132 | and exit with status zero. | |
133 | .TP | |
134 | .B "\-i, \-\-interactive" | |
135 | Write progress eyecandy to standard output while running. | |
136 | While walking the master tree, | |
137 | the | |
138 | .B gremlin | |
139 | shows which directory it's currently examining. | |
140 | While converting audio files, | |
141 | it shows a progress meter showing | |
142 | a bar chart of the job in progress, | |
143 | the percentage of the job which is complete, | |
144 | and an estimated time to completion. | |
145 | (This last starts out rather inaccurate, | |
146 | but seems to be pretty good after a couple of seconds.) | |
147 | All this is done automatically if standard output is a terminal; | |
148 | this option can be used to turn it on under other circumstances. | |
149 | .TP | |
150 | .B "\-n, \-\-no-act" | |
151 | Don't actually modify the filesystem. | |
152 | No files will be created or removed. | |
153 | .TP | |
154 | .BI "\-t, \-\-timeout=" timeout | |
155 | Only run for about | |
156 | .I timeout | |
157 | seconds. | |
158 | Once the timeout has expired, | |
159 | .B gremlin | |
160 | will try to finish what it's doing | |
161 | and then exit with status zero. | |
162 | .IP | |
163 | (This might seem a surprising choice of exit status. | |
164 | The idea is that the | |
165 | .B gremlin | |
166 | was asked to spend some amount of time converting files, | |
167 | and it has done that successfully.) | |
168 | .TP | |
169 | .BI "\-T, \-\-timeout-nasty=" timeout | |
170 | If the timeout set by the | |
171 | .B \-t | |
172 | option (above) has expired, | |
173 | and a further | |
174 | .I timeout | |
175 | seconds have elapsed | |
176 | but the | |
177 | .B gremlin | |
178 | still hasn't managed to wrap things up, | |
179 | then exit immediately with status 3, | |
180 | possibly leaving files partially converted, | |
181 | or other kinds of incompleteness. | |
182 | (A future run of the | |
183 | .B gremlin | |
184 | will notice this wreckage and clean it up.) | |
185 | . | |
186 | .\"-------------------------------------------------------------------------- | |
187 | .SH CONFIGURATION FILE | |
188 | . | |
189 | .SS "Lexical syntax" | |
190 | The | |
191 | .BR gremlin 's | |
192 | configuration file has a simple token-oriented lexical syntax. | |
193 | Whitespace acts to separate tokens but has no other meaning. | |
194 | A hash sign | |
195 | .RB ` # ' | |
196 | outside of a quoted string introduces a comment | |
197 | which extends to the end of the line; | |
198 | newlines otherwise just separate tokens, just like other whitespace. | |
199 | There are no `reserved words', | |
200 | but some names have special meanings, | |
201 | depending on the context. | |
202 | .PP | |
203 | Integers are written in decimal. | |
204 | (There is no provision for entering numbers in hex or octal.) | |
205 | .IP | |
206 | .I int | |
207 | ::= | |
208 | .I digit | |
209 | \&... | |
210 | .br | |
211 | .I digit | |
212 | ::= | |
213 | .B 0 | |
214 | | | |
215 | .B 1 | |
216 | | | |
217 | .B 2 | |
218 | | | |
219 | .B 3 | |
220 | | | |
221 | .B 4 | |
222 | | | |
223 | .B 5 | |
224 | | | |
225 | .B 6 | |
226 | | | |
227 | .B 7 | |
228 | | | |
229 | .B 8 | |
230 | | | |
231 | .B 9 | |
232 | .PP | |
233 | Strings (mostly used for pathnames and suchlike) | |
234 | are enclosed in double quotes | |
235 | .RB ` """" '; | |
236 | quotes and backslashes to be included in the string | |
237 | must be escaped by preceding them with a backslash | |
238 | .RB ` \e '. | |
239 | .IP | |
240 | .I string | |
241 | ::= | |
242 | .B """" | |
243 | .IR string-char ...\& | |
244 | .B """" | |
245 | .br | |
246 | .I string-char | |
247 | ::= | |
248 | any character other than | |
249 | .B """" | |
250 | or | |
251 | .B \e | |
252 | .br | |
253 | \h'4m'| | |
254 | .B "\e""" | |
255 | | | |
256 | .B \e\e | |
257 | . | |
258 | .SS "Top-level syntax" | |
259 | At a high level, | |
260 | the configuration consists of a sequence of | |
261 | .IR "top-level items" . | |
262 | .IP | |
263 | .I config | |
264 | ::= | |
265 | .I toplevel-item | |
266 | \&... | |
267 | . | |
268 | .SS "Global settings" | |
269 | Miscellaneous configuration for the whole program | |
270 | goes in a top-level | |
271 | .B vars | |
272 | section. | |
273 | .IP | |
274 | .I toplevel-item | |
275 | ::= | |
276 | .I vars-section | |
277 | .br | |
278 | .I vars-section | |
279 | ::= | |
280 | .B vars | |
281 | .B { | |
282 | .IR var-setting | |
283 | \&...\& | |
284 | .B } | |
285 | .PP | |
286 | There may be multiple such sections. | |
287 | The same variable may be set more than once; | |
288 | if that happens, | |
289 | only the last such setting has affect. | |
290 | .IP | |
291 | .I var-setting | |
292 | ::= | |
293 | .B master | |
294 | .B = | |
295 | .I path | |
296 | .br | |
297 | .I path | |
298 | ::= | |
299 | .I string | |
300 | .PP | |
301 | The | |
302 | .B master | |
303 | variable holds the pathname of the top of the master tree. | |
304 | .PP | |
305 | There are, at present, no other global settings. | |
306 | . | |
307 | .SS "Target definitions" | |
308 | The other kind of top-level configuration item | |
309 | defines a target directory | |
310 | to be constructed or updated | |
311 | by the | |
312 | .BR gremlin . | |
313 | .IP | |
314 | .I toplevel-item | |
315 | ::= | |
316 | .I target-def | |
317 | .br | |
318 | .I target-def | |
319 | ::= | |
320 | .B target | |
321 | .I path | |
322 | .B { | |
323 | .I type-clause | |
324 | \&...\& | |
325 | .B } | |
326 | .br | |
327 | .I type-clause | |
328 | ::= | |
329 | .B type | |
330 | .I type | |
331 | .B { | |
332 | .I policy | |
333 | \&...\& | |
334 | .B } | |
335 | .PP | |
336 | A | |
337 | .B target | |
338 | definition tells the | |
339 | .B gremlin | |
340 | to populate a directory tree, | |
341 | named rooted at the given | |
342 | .IR path . | |
343 | The body of the target definition consists of | |
344 | a sequence of | |
345 | .B type | |
346 | clauses | |
347 | which explain what to do with different kinds of file. | |
348 | The possible | |
349 | .I type | |
350 | tokens are as follows. | |
351 | .TP | |
352 | .B audio | |
353 | Encoded audio files, | |
354 | which can be decoded by the GStreamer library. | |
355 | .TP | |
356 | .B image | |
357 | Image files, | |
358 | which can be decoded by the Python Imaging Library. | |
359 | .PP | |
360 | The body of the type clause defines a | |
361 | .I policy | |
362 | for converting files of that type. | |
363 | . | |
364 | .SS "Policy descriptions" | |
365 | There are two kinds of | |
366 | .I primitive | |
367 | policies, | |
368 | which are described in full below: | |
369 | .BR accept , | |
370 | which copies (or links) a master file | |
371 | if its format is appropriate, | |
372 | or does nothing; | |
373 | and | |
374 | .BR convert , | |
375 | which converts a master file into a chosen format, | |
376 | and (in principle) should always succeed. | |
377 | There are also two ways to build up | |
378 | .I compound | |
379 | policies from simpler ones. | |
380 | .IP | |
381 | .I policy | |
382 | ::= | |
383 | .B and | |
384 | .B { | |
385 | .I policy | |
386 | \&...\& | |
387 | .B } | |
388 | .br | |
389 | \h'4m'| | |
390 | .B or | |
391 | .B { | |
392 | .I policy | |
393 | \&...\& | |
394 | .B } | |
395 | .PP | |
396 | The | |
397 | .B and | |
398 | policy applies | |
399 | .I all | |
400 | of its operand policies, | |
401 | potentially producing multiple output files. | |
402 | .PP | |
403 | The body of a | |
404 | .I type-clause | |
405 | consists of a sequence of policies | |
406 | which are implicitly combined together in this way. | |
407 | .PP | |
408 | The | |
409 | .B or | |
410 | policy | |
411 | tries its operand policies in turn, | |
412 | in the order specified, | |
413 | until one of them succeeds; | |
414 | no more policies are tried after this. | |
415 | .IP | |
416 | .I policy | |
417 | ::= | |
418 | .B accept | |
419 | .I format-spec | |
420 | .br | |
421 | \h'4m'| | |
422 | .B convert | |
423 | .I format-spec | |
424 | .IP | |
425 | .I format-spec | |
426 | ::= | |
427 | .I format-name | |
428 | .br | |
429 | \h'4m'| | |
430 | .I format-name | |
431 | .B { | |
432 | .I format-prop | |
433 | \&...\& | |
434 | .B } | |
435 | .PP | |
436 | (The possible | |
437 | .IR format-name s | |
438 | and the corresponding | |
439 | .IR format-spec s | |
440 | are described in the section below.) | |
441 | .PP | |
442 | The | |
443 | .B convert | |
444 | policy converts a file to the specified format. | |
445 | More specifically: | |
446 | if the file's format already matches the | |
447 | .I format-spec | |
448 | then it is copied to the target directory. | |
449 | (Indeed, if possible, | |
450 | the file is hard linked into the target directory.) | |
451 | If the file's format doesn't match, | |
452 | then the | |
453 | .B gremlin | |
454 | converts it, | |
455 | producing an output file of the requested format. | |
456 | .PP | |
457 | The | |
458 | .B accept | |
459 | policy copies or links a file if its format matches the | |
460 | .IR format-spec , | |
461 | just as | |
462 | .B convert | |
463 | does. | |
464 | However, if the file doesn't match then | |
465 | .B accept | |
466 | fails. | |
467 | .PP | |
468 | The usual use of | |
469 | .B accept | |
470 | is within an | |
471 | .B or | |
472 | block. | |
473 | For example, suppose that the master tree mostly contains | |
474 | losslessly encoded files, such as FLAC, | |
475 | and we usually want to produce Ogg Vorbis | |
476 | for use on devices with limited storage capacity; | |
477 | but some of the master files are only available as MP3, | |
478 | and re-encoding MP3 as Ogg Vorbis won't be good for sound quality. | |
479 | Therefore, you can say something like | |
480 | .IP | |
481 | .nf | |
482 | .ft B | |
483 | or { | |
484 | accept mp3 { bitrate = 160 } | |
485 | convert ogg-vorbis { bitrate = 128 } | |
486 | } | |
487 | .fi | |
488 | .ft P | |
489 | .PP | |
490 | which means: | |
491 | if a master file is an MP3 file with bitrate approximately 160kb/s or less, | |
492 | then copy it; | |
493 | otherwise, convert the file to Ogg Vorbis, at about 128kb/s. | |
494 | .PP | |
495 | It's possible that even a simple policy | |
496 | acting on the files in a master directory | |
497 | will come up with multiple ways | |
498 | to produce the same output file. | |
499 | The rule used to decide is as follows: | |
500 | if the | |
501 | .B gremlin | |
502 | can make the output file by copying one of the master files | |
503 | then it does that; | |
504 | otherwise it converts one of the inputs chosen arbitrarily. | |
505 | For example, | |
506 | suppose that a policy for | |
507 | .B audio | |
508 | files says | |
509 | .IP | |
510 | .B convert ogg-vorbis | |
511 | .PP | |
512 | and the master directory contains | |
513 | .B foo.flac | |
514 | and | |
515 | .BR foo.ogg ; | |
516 | then it will copy | |
517 | .B foo.ogg | |
518 | and ignore | |
519 | .BR foo.flac . | |
520 | If, instead, the master contains | |
521 | .B foo.flac | |
522 | and | |
523 | .BR foo.mp3 , | |
524 | then one of these will be converted, | |
525 | but it's hard to predict which. | |
526 | . | |
527 | .SS "Audio formats" | |
528 | Two audio | |
529 | .IR format-type s | |
530 | are defined. | |
531 | .PP | |
532 | All audio formats support a | |
533 | .B bitrate | |
534 | property. | |
535 | .IP | |
536 | .I format-prop | |
537 | ::= | |
538 | .B bitrate | |
539 | .B = | |
540 | .I int | |
541 | .PP | |
542 | The bitrate is expressed in kilobits per second. | |
543 | For an existing file to match a | |
544 | .I format-spec | |
545 | containing a | |
546 | .B bitrate | |
547 | property, | |
548 | the file's bitrate must be less than | |
549 | the specified bitrate times a fudge factor | |
550 | (currently sqrt(2)). | |
551 | (The | |
552 | .B bitrate | |
553 | property is notionally the desired | |
554 | .I output | |
555 | bitrate; | |
556 | the | |
557 | .B gremlin | |
558 | assumes that it's better to make output files a bit larger | |
559 | than to re-encode an already lossily compressed master file.) | |
560 | .PP | |
561 | At present, the audio formats define no other properties. | |
562 | .TP | |
563 | .B mp3 | |
564 | The MP3 format that everyone knows and loves. | |
565 | For encoding, the | |
566 | .B gremlin | |
567 | uses Lame, | |
568 | and stores metadata in an ID3v2 tag; | |
569 | it also tries to store an ID3v1.1 tag, | |
570 | but this can fail for a number of reasons | |
571 | (e.g., if the genre can't be represented, | |
572 | or text contains characters outside of the ISO 8859-1 character set | |
573 | used in ID3v1 tags). | |
574 | .TP | |
575 | .B ogg-vorbis | |
576 | Vorbis-encoded audio in an Ogg container, | |
577 | as defined by the Xiph.Org Foundation. | |
578 | On encoding, the | |
579 | .B bitrate | |
580 | parameter is actually mapped to a quality setting | |
581 | chosen to produce approximately the right bitrate. | |
582 | . | |
583 | .SS "Image formats" | |
584 | Three image | |
585 | .IR format-type s | |
586 | are defined. | |
587 | .PP | |
588 | All image formats support a | |
589 | .B size | |
590 | property. | |
591 | .IP | |
592 | .I format-prop | |
593 | ::= | |
594 | .B size | |
595 | .B = | |
596 | .I int | |
597 | .PP | |
598 | The size provides an upper bound on the width and height of the image. | |
599 | A master file will only match if | |
600 | both its width and height are | |
601 | less than the stated size. | |
602 | On output, the image will be scaled to the right size, | |
603 | preserving its aspect ratio. | |
604 | .TP | |
605 | .B jpeg | |
606 | The JFIF format, defined by the Joint Photographic Experts Group. | |
607 | The following additional properties can be set; | |
608 | they affect output only. | |
609 | .RS | |
610 | .TP | |
611 | .B optimize | |
612 | Spend longer to select optimal encoder settings. | |
613 | .TP | |
614 | .B progressive | |
615 | Make a progressively-rendering output file. | |
616 | This isn't usually a good idea. | |
617 | .TP | |
618 | .BI "quality = " int | |
619 | Set the image quality (at the expense of file size). | |
620 | This is a percentage; the default is 75. | |
621 | .RE | |
622 | .TP | |
623 | .B png | |
624 | The Portable Network Graphics format, | |
625 | originally defined in RFC2083. | |
626 | The following additional properties can be set; | |
627 | they affect output only. | |
628 | .RS | |
629 | .TP | |
630 | .B optimize | |
631 | Spend longer to try to make the output file smaller. | |
632 | .RE | |
633 | .TP | |
634 | .B bmp | |
635 | The Windows BMP format. | |
636 | There are no additional properties. | |
637 | . | |
638 | .SS "Example file" | |
639 | The following is the author's configuration file. | |
640 | I have an archive which mostly consists of FLAC files, | |
641 | with a few MP3 files where I've been unable to obtain physical CDs. | |
642 | I generate two output trees. | |
643 | One mostly contains Ogg Vorbis files, | |
644 | but tolerates occasional MP3 | |
645 | rather than suffer the quality loss of re-encoding. | |
646 | It also generates small BMP-format images from cover art, | |
647 | because I have an old portable audio player | |
648 | which runs the free RockBox firmware, | |
649 | whose player is only capable of displaying such images. | |
650 | .IP | |
651 | .nf | |
652 | .ft B | |
653 | ### -*-conf-*- | |
654 | ||
655 | vars { | |
656 | master = "/mnt/jb/master" | |
657 | } | |
658 | ||
659 | target "/mnt/jb/gremlin/ogg-vorbis-128" { | |
660 | type audio { | |
661 | or { | |
662 | accept mp3 { bitrate = 160 } | |
663 | convert ogg-vorbis { bitrate = 128 } | |
664 | } | |
665 | } | |
666 | type image { | |
667 | or { | |
668 | accept png | |
669 | convert jpeg { quality = 7 } | |
670 | } | |
671 | convert bmp { size = 75 } | |
672 | } | |
673 | } | |
674 | ||
675 | target "/mnt/jb/gremlin/mp3-160" { | |
676 | type audio { | |
677 | convert mp3 { bitrate = 160 } | |
678 | } | |
679 | type image { | |
680 | or { | |
681 | accept png | |
682 | convert jpeg { quality = 7 } | |
683 | } | |
684 | } | |
685 | } | |
686 | .fi | |
687 | .ft P | |
688 | . | |
689 | .\"-------------------------------------------------------------------------- | |
690 | .SH BUGS | |
691 | . | |
692 | The | |
693 | .B gremlin | |
694 | makes no effort to process more than one file at a time. | |
695 | .PP | |
696 | It should probably support more audio formats. | |
697 | They're quite easy to add, | |
698 | but I don't have a good feel for which formats are good. | |
699 | Patches and advice are welcome. | |
700 | .PP | |
701 | The | |
702 | .B and | |
703 | and | |
704 | .B or | |
705 | policy names are possibly confusing. | |
706 | They suggest that they work like the standard logical operators; | |
707 | while | |
708 | .B or | |
709 | sort of does, if you squint a bit, | |
710 | .B and | |
711 | certainly doesn't; | |
712 | on the other hand, it does try to do all of the things you ask of it. | |
713 | .PP | |
714 | .B gremlin | |
715 | is a very unhelpful name for the program. | |
716 | . | |
717 | .\"-------------------------------------------------------------------------- | |
718 | .SH AUTHOR | |
719 | Mark Wooding, <mdw@distorted.org.uk> | |
720 | . | |
721 | .SH SEE ALSO | |
722 | .BR hush (1), | |
723 | .BR rsync (1). | |
724 | . | |
725 | .\"----- That's all, folks -------------------------------------------------- |