3 * This program is distributed under the GNU General Public License, version 2.
4 * A copy of this license is included with this source.
6 * Copyright 2000-2005, Michael Smith <msmith@xiph.org>
8 * Portions from Vorbize, (c) Kenneth Arnold <kcarnold-xiph@arnoldnet.net>
9 * and libvorbis examples, (c) Monty <monty@xiph.org>
24 #include <sys/types.h>
26 #if defined WIN32 || defined _WIN32
36 /* fallback for stand-alone compiles */
38 # define PACKAGE "oggenc"
41 # define VERSION "unknown"
44 #define CHUNK 4096 /* We do reads, etc. in multiples of this */
46 struct option long_options
[] = {
49 {"skeleton",no_argument
,NULL
, 'k'},
56 {"name-remove",1,0,'X'},
57 {"name-replace",1,0,'P'},
64 {"raw-endianness",1,0, 0},
66 {"min-bitrate",1,0,'m'},
67 {"max-bitrate",1,0,'M'},
76 {"advanced-encode-option", 1, 0, 0},
77 {"discard-comments", 0, 0, 0},
79 {"ignorelength", 0, 0, 0},
81 {"lyrics-language",1,0,'Y'},
85 static char *generate_name_string(char *format
, char *remove_list
,
86 char *replace_list
, char *artist
, char *title
, char *album
,
87 char *track
, char *date
, char *genre
);
88 static void parse_options(int argc
, char **argv
, oe_options
*opt
);
89 static void build_comments(vorbis_comment
*vc
, oe_options
*opt
, int filenum
,
90 char **artist
,char **album
, char **title
, char **tracknum
, char **date
,
92 static void usage(void);
94 int main(int argc
, char **argv
)
98 NULL
, 0, NULL
, 0, NULL
, 0, NULL
, 0, NULL
, 0,
99 NULL
, 0, NULL
, 0, NULL
, 0, NULL
, 0, NULL
, 0,
102 NULL
, DEFAULT_NAMEFMT_REMOVE
, DEFAULT_NAMEFMT_REPLACE
,
108 input_format raw_format
= {NULL
, 0, raw_open
, wav_close
, "raw",
109 N_("RAW file reader")};
117 get_args_from_ucs16(&argc
, &argv
);
119 setlocale(LC_ALL
, "");
120 bindtextdomain(PACKAGE
, LOCALEDIR
);
123 parse_options(argc
, argv
, &opt
);
127 fprintf(stderr
, _("ERROR: No input files specified. Use -h for help.\n"));
132 infiles
= argv
+ optind
;
133 numfiles
= argc
- optind
;
136 /* Now, do some checking for illegal argument combinations */
138 for(i
= 0; i
< numfiles
; i
++)
140 if(!strcmp(infiles
[i
], "-") && numfiles
> 1)
142 fprintf(stderr
, _("ERROR: Multiple files specified when using stdin\n"));
147 if(numfiles
> 1 && opt
.outfile
)
149 fprintf(stderr
, _("ERROR: Multiple input files with specified output filename: suggest using -n\n"));
155 /* We randomly pick a serial number. This is then incremented for each
156 file. The random seed includes the PID so two copies of oggenc that
157 start in the same second will generate different serial numbers. */
158 srand(time(NULL
) ^ getpid());
161 opt
.skeleton_serial
= opt
.serial
+ numfiles
;
162 opt
.kate_serial
= opt
.skeleton_serial
+ numfiles
;
164 for(i
= 0; i
< numfiles
; i
++)
166 /* Once through the loop for each file */
171 FILE *in
, *out
= NULL
;
173 int closeout
= 0, closein
= 0;
174 char *artist
=NULL
, *album
=NULL
, *title
=NULL
, *track
=NULL
;
175 char *date
=NULL
, *genre
=NULL
;
176 char *lyrics
=NULL
, *lyrics_language
=NULL
;
177 input_format
*format
;
180 /* Set various encoding defaults */
182 enc_opts
.serialno
= opt
.serial
++;
183 enc_opts
.skeleton_serialno
= opt
.skeleton_serial
++;
184 enc_opts
.kate_serialno
= opt
.kate_serial
++;
185 enc_opts
.progress_update
= update_statistics_full
;
186 enc_opts
.start_encode
= start_encode_full
;
187 enc_opts
.end_encode
= final_statistics
;
188 enc_opts
.error
= encode_error
;
189 enc_opts
.comments
= &vc
;
190 enc_opts
.copy_comments
= opt
.copy_comments
;
191 enc_opts
.with_skeleton
= opt
.with_skeleton
;
192 enc_opts
.ignorelength
= opt
.ignorelength
;
194 /* OK, let's build the vorbis_comments structure */
195 build_comments(&vc
, &opt
, i
, &artist
, &album
, &title
, &track
,
200 if(i
>= opt
.lyrics_count
)
205 lyrics
= opt
.lyrics
[i
];
208 if(opt
.lyrics_language_count
)
210 if(i
>= opt
.lyrics_language_count
)
213 fprintf(stderr
, _("WARNING: Insufficient lyrics languages specified, defaulting to final lyrics language.\n"));
214 lyrics_language
= opt
.lyrics_language
[opt
.lyrics_language_count
-1];
217 lyrics_language
= opt
.lyrics_language
[i
];
220 if(!strcmp(infiles
[i
], "-"))
233 in
= oggenc_fopen(infiles
[i
], "rb", opt
.isutf8
);
237 fprintf(stderr
, _("ERROR: Cannot open input file \"%s\": %s\n"), infiles
[i
], strerror(errno
));
246 /* Now, we need to select an input audio format - we do this before opening
247 the output file so that we don't end up with a 0-byte file if the input
248 file can't be read */
253 enc_opts
.rate
=opt
.raw_samplerate
;
254 enc_opts
.channels
=opt
.raw_channels
;
255 enc_opts
.samplesize
=opt
.raw_samplesize
;
256 enc_opts
.endianness
=opt
.raw_endianness
;
258 format
= &raw_format
;
259 format
->open_func(in
, &enc_opts
, NULL
, 0);
264 format
= open_audio_file(in
, &enc_opts
);
268 fprintf(stderr
, _("Opening with %s module: %s\n"),
269 format
->format
, format
->description
);
277 fprintf(stderr
, _("ERROR: Input file \"%s\" is not a supported format\n"), infiles
[i
]?infiles
[i
]:"(stdin)");
284 if(enc_opts
.rate
<= 0)
286 fprintf(stderr
, _("ERROR: Input file \"%s\" has invalid sampling rate\n"), infiles
[i
]?infiles
[i
]:"(stdin)");
293 /* Ok. We can read the file - so now open the output file */
295 if(opt
.outfile
&& !strcmp(opt
.outfile
, "-"))
304 out_fn
= strdup(opt
.outfile
);
308 out_fn
= generate_name_string(opt
.namefmt
, opt
.namefmt_remove
,
309 opt
.namefmt_replace
, artist
, title
, album
, track
,date
,
312 /* This bit was widely derided in mid-2002, so it's been removed */
316 out_fn = malloc(strlen(title) + 5);
317 strcpy(out_fn, title);
318 strcat(out_fn, ".ogg");
323 /* Create a filename from existing filename, replacing extension with .ogg or .oga */
327 /* if adding Skeleton or Kate, we're not Vorbis I anymore */
328 extension
= (opt
.with_skeleton
|| opt
.lyrics_count
>0) ? ".oga" : ".ogg";
331 end
= strrchr(infiles
[i
], '.');
332 end
= end
?end
:(start
+ strlen(infiles
[i
])+1);
334 out_fn
= malloc(end
- start
+ 5);
335 strncpy(out_fn
, start
, end
-start
);
336 out_fn
[end
-start
] = 0;
337 strcat(out_fn
, extension
);
340 /* if adding skeleton or kate, we're not Vorbis I anymore */
341 if (opt
.with_skeleton
|| opt
.lyrics_count
>0)
342 out_fn
= strdup("default.oga");
344 out_fn
= strdup("default.ogg");
345 fprintf(stderr
, _("WARNING: No filename, defaulting to \"%s\"\n"), out_fn
);
348 /* Create any missing subdirectories, if possible */
349 if(create_directories(out_fn
, opt
.isutf8
)) {
352 fprintf(stderr
, _("ERROR: Could not create required subdirectories for output filename \"%s\"\n"), out_fn
);
358 if(infiles
[i
] && !strcmp(infiles
[i
], out_fn
)) {
359 fprintf(stderr
, _("ERROR: Input filename is the same as output filename \"%s\"\n"), out_fn
);
365 out
= oggenc_fopen(out_fn
, "wb", opt
.isutf8
);
370 fprintf(stderr
, _("ERROR: Cannot open output file \"%s\": %s\n"), out_fn
, strerror(errno
));
378 /* Now, set the rest of the options */
380 enc_opts
.comments
= &vc
;
383 enc_opts
.filename
= NULL
;
384 enc_opts
.infilename
= NULL
;
385 utf8_decode(out_fn
, &enc_opts
.filename
);
386 utf8_decode(infiles
[i
], &enc_opts
.infilename
);
388 enc_opts
.filename
= strdup(out_fn
);
389 enc_opts
.infilename
= strdup(infiles
[i
]);
392 enc_opts
.filename
= out_fn
;
393 enc_opts
.infilename
= infiles
[i
];
395 enc_opts
.managed
= opt
.managed
;
396 enc_opts
.bitrate
= opt
.nominal_bitrate
;
397 enc_opts
.min_bitrate
= opt
.min_bitrate
;
398 enc_opts
.max_bitrate
= opt
.max_bitrate
;
399 enc_opts
.quality
= opt
.quality
;
400 enc_opts
.quality_set
= opt
.quality_set
;
401 enc_opts
.advopt
= opt
.advopt
;
402 enc_opts
.advopt_count
= opt
.advopt_count
;
403 enc_opts
.lyrics
= lyrics
;
404 enc_opts
.lyrics_language
= lyrics_language
;
406 if(opt
.resamplefreq
&& opt
.resamplefreq
!= enc_opts
.rate
) {
407 int fromrate
= enc_opts
.rate
;
410 enc_opts
.resamplefreq
= opt
.resamplefreq
;
411 if(setup_resample(&enc_opts
)) {
416 fprintf(stderr
, _("Resampling input from %d Hz to %d Hz\n"), fromrate
, opt
.resamplefreq
);
420 if(enc_opts
.channels
== 2) {
421 setup_downmix(&enc_opts
);
423 fprintf(stderr
, _("Downmixing stereo to mono\n"));
426 fprintf(stderr
, _("WARNING: Can't downmix except from stereo to mono\n"));
431 if(opt
.scale
> 0.f
) {
432 setup_scaler(&enc_opts
, opt
.scale
);
434 fprintf(stderr
, _("Scaling input to %f\n"), opt
.scale
);
438 if(enc_opts
.total_samples_per_channel
<= 0)
439 enc_opts
.progress_update
= update_statistics_notime
;
443 enc_opts
.start_encode
= start_encode_null
;
444 enc_opts
.progress_update
= update_statistics_null
;
445 enc_opts
.end_encode
= final_statistics_null
;
448 if(oe_encode(&enc_opts
))
452 clear_scaler(&enc_opts
);
454 clear_downmix(&enc_opts
);
456 clear_resample(&enc_opts
);
459 if(out_fn
) free(out_fn
);
460 if(opt
.outfile
) free(opt
.outfile
);
462 if(enc_opts
.filename
) free(enc_opts
.filename
);
463 if(enc_opts
.infilename
) free(enc_opts
.infilename
);
465 vorbis_comment_clear(&vc
);
466 format
->close_func(enc_opts
.readdata
);
472 }/* Finished this file, loop around to next... */
478 static void usage(void)
480 fprintf(stdout
, _("oggenc from %s %s"), PACKAGE
, VERSION
);
481 fprintf(stdout
, _(" by the Xiph.Org Foundation (http://www.xiph.org/)\n\n"));
482 fprintf(stdout
, _("Usage: oggenc [options] inputfile [...]\n\n"));
483 fprintf(stdout
, _("OPTIONS:\n"
485 " -Q, --quiet Produce no output to stderr\n"
486 " -h, --help Print this help text\n"
487 " -V, --version Print the version number\n"));
489 " -k, --skeleton Adds an Ogg Skeleton bitstream\n"
490 " -r, --raw Raw mode. Input files are read directly as PCM data\n"
491 " -B, --raw-bits=n Set bits/sample for raw input; default is 16\n"
492 " -C, --raw-chan=n Set number of channels for raw input; default is 2\n"
493 " -R, --raw-rate=n Set samples/sec for raw input; default is 44100\n"
494 " --raw-endianness 1 for bigendian, 0 for little (defaults to 0)\n"));
496 " -b, --bitrate Choose a nominal bitrate to encode at. Attempt\n"
497 " to encode at a bitrate averaging this. Takes an\n"
498 " argument in kbps. By default, this produces a VBR\n"
499 " encoding, equivalent to using -q or --quality.\n"
500 " See the --managed option to use a managed bitrate\n"
501 " targetting the selected bitrate.\n"));
503 " --managed Enable the bitrate management engine. This will allow\n"
504 " much greater control over the precise bitrate(s) used,\n"
505 " but encoding will be much slower. Don't use it unless\n"
506 " you have a strong need for detailed control over\n"
507 " bitrate, such as for streaming.\n"));
509 " -m, --min-bitrate Specify a minimum bitrate (in kbps). Useful for\n"
510 " encoding for a fixed-size channel. Using this will\n"
511 " automatically enable managed bitrate mode (see\n"
513 " -M, --max-bitrate Specify a maximum bitrate in kbps. Useful for\n"
514 " streaming applications. Using this will automatically\n"
515 " enable managed bitrate mode (see --managed).\n"));
517 " --advanced-encode-option option=value\n"
518 " Sets an advanced encoder option to the given value.\n"
519 " The valid options (and their values) are documented\n"
520 " in the man page supplied with this program. They are\n"
521 " for advanced users only, and should be used with\n"
524 " -q, --quality Specify quality, between -1 (very low) and 10 (very\n"
525 " high), instead of specifying a particular bitrate.\n"
526 " This is the normal mode of operation.\n"
527 " Fractional qualities (e.g. 2.75) are permitted\n"
528 " The default quality level is 3.\n"));
530 " --resample n Resample input data to sampling rate n (Hz)\n"
531 " --downmix Downmix stereo to mono. Only allowed on stereo\n"
533 " -s, --serial Specify a serial number for the stream. If encoding\n"
534 " multiple files, this will be incremented for each\n"
535 " stream after the first.\n"));
537 " --discard-comments Prevents comments in FLAC and Ogg FLAC files from\n"
538 " being copied to the output Ogg Vorbis file.\n"
539 " --ignorelength Ignore the datalength in Wave headers. This allows\n"
540 " support for files > 4GB and STDIN data streams. \n"
544 " -o, --output=fn Write file to fn (only valid in single-file mode)\n"
545 " -n, --names=string Produce filenames as this string, with %%a, %%t, %%l,\n"
546 " %%n, %%d replaced by artist, title, album, track number,\n"
547 " and date, respectively (see below for specifying these).\n"
548 " %%%% gives a literal %%.\n"));
550 " -X, --name-remove=s Remove the specified characters from parameters to the\n"
551 " -n format string. Useful to ensure legal filenames.\n"
552 " -P, --name-replace=s Replace characters removed by --name-remove with the\n"
553 " characters specified. If this string is shorter than the\n"
554 " --name-remove list or is not specified, the extra\n"
555 " characters are just removed.\n"
556 " Default settings for the above two arguments are platform\n"
559 " --utf8 Tells oggenc that the command line parameters date, title,\n"
560 " album, artist, genre, and comment are already in UTF-8.\n"
561 " On Windows, this switch applies to file names too.\n"
562 " -c, --comment=c Add the given string as an extra comment. This may be\n"
563 " used multiple times. The argument should be in the\n"
564 " format \"tag=value\".\n"
565 " -d, --date Date for track (usually date of performance)\n"));
567 " -N, --tracknum Track number for this track\n"
568 " -t, --title Title for this track\n"
569 " -l, --album Name of album\n"
570 " -a, --artist Name of artist\n"
571 " -G, --genre Genre of track\n"));
573 " -L, --lyrics Include lyrics from given file (.srt or .lrc format)\n"
574 " -Y, --lyrics-language Sets the language for the lyrics\n"));
576 " If multiple input files are given, then multiple\n"
577 " instances of the previous eight arguments will be used,\n"
578 " in the order they are given. If fewer titles are\n"
579 " specified than files, OggEnc will print a warning, and\n"
580 " reuse the final one for the remaining files. If fewer\n"
581 " track numbers are given, the remaining files will be\n"
582 " unnumbered. If fewer lyrics are given, the remaining\n"
583 " files will not have lyrics added. For the others, the\n"
584 " final tag will be reused for all others without warning\n"
585 " (so you can specify a date once, for example, and have\n"
586 " it used for all the files)\n"
590 " OggEnc input files must currently be 24, 16, or 8 bit PCM Wave, AIFF, or AIFF/C\n"
591 " files, 32 bit IEEE floating point Wave, and optionally FLAC or Ogg FLAC. Files\n"
592 " may be mono or stereo (or more channels) and any sample rate.\n"
593 " Alternatively, the --raw option may be used to use a raw PCM data file, which\n"
594 " must be 16 bit stereo little-endian PCM ('headerless Wave'), unless additional\n"
595 " parameters for raw mode are specified.\n"
596 " You can specify taking the file from stdin by using - as the input filename.\n"
597 " In this mode, output is to stdout unless an output filename is specified\n"
599 " Lyrics files may be in SubRip (.srt) or LRC (.lrc) format\n"
603 static int strncpy_filtered(char *dst
, char *src
, int len
, char *remove_list
,
606 char *hit
, *drop_margin
;
609 if(remove_list
== NULL
|| *remove_list
== 0)
611 strncpy(dst
, src
, len
-1);
616 drop_margin
= remove_list
+ (replace_list
== NULL
?0:strlen(replace_list
));
618 while(*src
&& used
< len
-1)
620 if((hit
= strchr(remove_list
, *src
)) != NULL
)
622 if(hit
< drop_margin
)
624 *dst
++ = replace_list
[hit
- remove_list
];
640 static char *generate_name_string(char *format
, char *remove_list
,
641 char *replace_list
, char *artist
, char *title
, char *album
,
642 char *track
, char *date
, char *genre
)
650 buffer
= calloc(CHUNK
+1,1);
653 while(*format
&& used
< buflen
)
662 *(buffer
+(used
++)) = '%';
665 string
= artist
?artist
:_("(none)");
666 used
+= strncpy_filtered(buffer
+used
, string
, buflen
-used
,
667 remove_list
, replace_list
);
670 string
= date
?date
:_("(none)");
671 used
+= strncpy_filtered(buffer
+used
, string
, buflen
-used
,
672 remove_list
, replace_list
);
675 string
= genre
?genre
:_("(none)");
676 used
+= strncpy_filtered(buffer
+used
, string
, buflen
-used
,
677 remove_list
, replace_list
);
680 string
= title
?title
:_("(none)");
681 used
+= strncpy_filtered(buffer
+used
, string
, buflen
-used
,
682 remove_list
, replace_list
);
685 string
= album
?album
:_("(none)");
686 used
+= strncpy_filtered(buffer
+used
, string
, buflen
-used
,
687 remove_list
, replace_list
);
690 string
= track
?track
:_("(none)");
691 used
+= strncpy_filtered(buffer
+used
, string
, buflen
-used
,
692 remove_list
, replace_list
);
695 fprintf(stderr
, _("WARNING: Ignoring illegal escape character '%c' in name format\n"), *(format
- 1));
700 *(buffer
+ (used
++)) = next
;
706 static void parse_options(int argc
, char **argv
, oe_options
*opt
)
709 int option_index
= 1;
711 while((ret
= getopt_long(argc
, argv
, "a:b:B:c:C:d:G:hkl:L:m:M:n:N:o:P:q:QrR:s:t:VX:Y:",
712 long_options
, &option_index
)) != -1)
717 if(!strcmp(long_options
[option_index
].name
, "skeleton")) {
718 opt
->with_skeleton
= 1;
720 else if(!strcmp(long_options
[option_index
].name
, "managed")) {
724 _("Enabling bitrate management engine\n"));
728 else if(!strcmp(long_options
[option_index
].name
,
730 if (opt
->rawmode
!= 1)
733 fprintf(stderr
, _("WARNING: Raw endianness specified for non-raw data. Assuming input is raw.\n"));
735 if(sscanf(optarg
, "%d", &opt
->raw_endianness
) != 1) {
736 fprintf(stderr
, _("WARNING: Couldn't read endianness argument \"%s\"\n"), optarg
);
737 opt
->raw_endianness
= 0;
740 else if(!strcmp(long_options
[option_index
].name
,
742 if(sscanf(optarg
, "%d", &opt
->resamplefreq
) != 1) {
743 fprintf(stderr
, _("WARNING: Couldn't read resampling frequency \"%s\"\n"), optarg
);
744 opt
->resamplefreq
= 0;
746 if(opt
->resamplefreq
< 100) /* User probably specified it
749 _("WARNING: Resample rate specified as %d Hz. Did you mean %d Hz?\n"),
750 opt
->resamplefreq
, opt
->resamplefreq
*1000);
752 else if(!strcmp(long_options
[option_index
].name
, "downmix")) {
755 else if(!strcmp(long_options
[option_index
].name
, "scale")) {
756 opt
->scale
= atof(optarg
);
757 if(sscanf(optarg
, "%f", &opt
->scale
) != 1) {
759 fprintf(stderr
, _("WARNING: Couldn't parse scaling factor \"%s\"\n"),
763 else if(!strcmp(long_options
[option_index
].name
, "utf8")) {
766 else if(!strcmp(long_options
[option_index
].name
, "advanced-encode-option")) {
767 char *arg
= strdup(optarg
);
770 if(strcmp("disable_coupling",arg
)){
771 val
= strchr(arg
, '=');
773 fprintf(stderr
, _("No value for advanced encoder option found\n"));
781 opt
->advopt
= realloc(opt
->advopt
, (++opt
->advopt_count
)*sizeof(adv_opt
));
782 opt
->advopt
[opt
->advopt_count
- 1].arg
= arg
;
783 opt
->advopt
[opt
->advopt_count
- 1].val
= val
;
785 else if(!strcmp(long_options
[option_index
].name
, "discard-comments")) {
786 opt
->copy_comments
= 0;
788 else if(!strcmp(long_options
[option_index
].name
, "ignorelength")) {
789 opt
->ignorelength
= 1;
793 fprintf(stderr
, _("Internal error parsing command line options\n"));
799 opt
->artist
= realloc(opt
->artist
, (++opt
->artist_count
)*sizeof(char *));
800 opt
->artist
[opt
->artist_count
- 1] = strdup(optarg
);
803 if(strchr(optarg
, '=') == NULL
) {
804 fprintf(stderr
, _("WARNING: Illegal comment used (\"%s\"), ignoring.\n"), optarg
);
807 opt
->comments
= realloc(opt
->comments
, (++opt
->comment_count
)*sizeof(char *));
808 opt
->comments
[opt
->comment_count
- 1] = strdup(optarg
);
811 opt
->dates
= realloc(opt
->dates
, (++opt
->date_count
)*sizeof(char *));
812 opt
->dates
[opt
->date_count
- 1] = strdup(optarg
);
815 opt
->genre
= realloc(opt
->genre
, (++opt
->genre_count
)*sizeof(char *));
816 opt
->genre
[opt
->genre_count
- 1] = strdup(optarg
);
823 opt
->album
= realloc(opt
->album
, (++opt
->album_count
)*sizeof(char *));
824 opt
->album
[opt
->album_count
- 1] = strdup(optarg
);
827 /* Would just use atoi(), but that doesn't deal with unsigned
829 if(sscanf(optarg
, "%u", &opt
->serial
) != 1)
830 opt
->serial
= 0; /* Failed, so just set to zero */
832 opt
->fixedserial
= 1;
835 opt
->title
= realloc(opt
->title
, (++opt
->title_count
)*sizeof(char *));
836 opt
->title
[opt
->title_count
- 1] = strdup(optarg
);
839 if(sscanf(optarg
, "%d", &opt
->nominal_bitrate
)
841 fprintf(stderr
, _("WARNING: nominal bitrate \"%s\" not recognised\n"), optarg
);
842 opt
->nominal_bitrate
= -1;
847 if(sscanf(optarg
, "%d", &opt
->min_bitrate
)
849 fprintf(stderr
, _("WARNING: minimum bitrate \"%s\" not recognised\n"), optarg
);
850 opt
->min_bitrate
= -1;
855 _("Enabling bitrate management engine\n"));
860 if(sscanf(optarg
, "%d", &opt
->max_bitrate
)
862 fprintf(stderr
, _("WARNING: maximum bitrate \"%s\" not recognised\n"), optarg
);
863 opt
->max_bitrate
= -1;
868 _("Enabling bitrate management engine\n"));
873 if(sscanf(optarg
, "%f", &opt
->quality
) != 1) {
874 fprintf(stderr
, _("Quality option \"%s\" not recognised, ignoring\n"), optarg
);
879 if(opt
->quality
> 1.0f
)
882 fprintf(stderr
, _("WARNING: quality setting too high, setting to maximum quality.\n"));
888 fprintf(stderr
, _("WARNING: Multiple name formats specified, using final\n"));
891 opt
->namefmt
= strdup(optarg
);
894 if(opt
->namefmt_remove
&&
895 strcmp(opt
->namefmt_remove
, DEFAULT_NAMEFMT_REMOVE
))
897 fprintf(stderr
, _("WARNING: Multiple name format filters specified, using final\n"));
898 free(opt
->namefmt_remove
);
900 opt
->namefmt_remove
= strdup(optarg
);
903 if(opt
->namefmt_replace
&&
904 strcmp(opt
->namefmt_replace
, DEFAULT_NAMEFMT_REPLACE
))
906 fprintf(stderr
, _("WARNING: Multiple name format filter replacements specified, using final\n"));
907 free(opt
->namefmt_replace
);
909 opt
->namefmt_replace
= strdup(optarg
);
914 fprintf(stderr
, _("WARNING: Multiple output files specified, suggest using -n\n"));
917 opt
->outfile
= strdup(optarg
);
926 fprintf(stdout
, _("oggenc from %s %s\n"), PACKAGE
, VERSION
);
930 if (opt
->rawmode
!= 1)
933 fprintf(stderr
, _("WARNING: Raw bits/sample specified for non-raw data. Assuming input is raw.\n"));
935 if(sscanf(optarg
, "%u", &opt
->raw_samplesize
) != 1)
937 opt
->raw_samplesize
= 16; /* Failed, so just set to 16 */
938 fprintf(stderr
, _("WARNING: Invalid bits/sample specified, assuming 16.\n"));
940 if((opt
->raw_samplesize
!= 8) && (opt
->raw_samplesize
!= 16))
942 fprintf(stderr
, _("WARNING: Invalid bits/sample specified, assuming 16.\n"));
946 if (opt
->rawmode
!= 1)
949 fprintf(stderr
, _("WARNING: Raw channel count specified for non-raw data. Assuming input is raw.\n"));
951 if(sscanf(optarg
, "%u", &opt
->raw_channels
) != 1)
953 opt
->raw_channels
= 2; /* Failed, so just set to 2 */
954 fprintf(stderr
, _("WARNING: Invalid channel count specified, assuming 2.\n"));
958 opt
->tracknum
= realloc(opt
->tracknum
, (++opt
->track_count
)*sizeof(char *));
959 opt
->tracknum
[opt
->track_count
- 1] = strdup(optarg
);
962 if (opt
->rawmode
!= 1)
965 fprintf(stderr
, _("WARNING: Raw sample rate specified for non-raw data. Assuming input is raw.\n"));
967 if(sscanf(optarg
, "%u", &opt
->raw_samplerate
) != 1)
969 opt
->raw_samplerate
= 44100; /* Failed, so just set to 44100 */
970 fprintf(stderr
, _("WARNING: Invalid sample rate specified, assuming 44100.\n"));
974 opt
->with_skeleton
= 1;
978 opt
->lyrics
= realloc(opt
->lyrics
, (++opt
->lyrics_count
)*sizeof(char *));
979 opt
->lyrics
[opt
->lyrics_count
- 1] = strdup(optarg
);
980 opt
->with_skeleton
= 1;
982 fprintf(stderr
, _("WARNING: Kate support not compiled in; lyrics will not be included.\n"));
987 opt
->lyrics_language
= realloc(opt
->lyrics_language
, (++opt
->lyrics_language_count
)*sizeof(char *));
988 opt
->lyrics_language
[opt
->lyrics_language_count
- 1] = strdup(optarg
);
989 if (strlen(opt
->lyrics_language
[opt
->lyrics_language_count
- 1]) > 15) {
990 fprintf(stderr
, _("WARNING: language can not be longer than 15 characters; truncated.\n"));
991 opt
->lyrics_language
[opt
->lyrics_language_count
- 1][15] = 0;
994 fprintf(stderr
, _("WARNING: Kate support not compiled in; lyrics will not be included.\n"));
998 fprintf(stderr
, _("WARNING: Unknown option specified, ignoring->\n"));
1008 static void add_tag(vorbis_comment
*vc
, oe_options
*opt
,char *name
, char *value
)
1013 if (!utf8_validate(value
)) {
1014 fprintf(stderr
, _("'%s' is not valid UTF-8, cannot add\n"), name
?name
:"comment");
1017 vorbis_comment_add(vc
, value
);
1019 vorbis_comment_add_tag(vc
, name
, value
);
1022 else if(utf8_encode(value
, &utf8
) >= 0)
1025 vorbis_comment_add(vc
, utf8
);
1027 vorbis_comment_add_tag(vc
, name
, utf8
);
1031 fprintf(stderr
, _("Couldn't convert comment to UTF-8, cannot add\n"));
1034 static void build_comments(vorbis_comment
*vc
, oe_options
*opt
, int filenum
,
1035 char **artist
, char **album
, char **title
, char **tracknum
,
1036 char **date
, char **genre
)
1040 vorbis_comment_init(vc
);
1042 for(i
= 0; i
< opt
->comment_count
; i
++)
1043 add_tag(vc
, opt
, NULL
, opt
->comments
[i
]);
1045 if(opt
->title_count
)
1047 if(filenum
>= opt
->title_count
)
1050 fprintf(stderr
, _("WARNING: Insufficient titles specified, defaulting to final title.\n"));
1051 i
= opt
->title_count
-1;
1056 *title
= opt
->title
[i
];
1057 add_tag(vc
, opt
, "title", opt
->title
[i
]);
1060 if(opt
->artist_count
)
1062 if(filenum
>= opt
->artist_count
)
1063 i
= opt
->artist_count
-1;
1067 *artist
= opt
->artist
[i
];
1068 add_tag(vc
, opt
, "artist", opt
->artist
[i
]);
1071 if(opt
->genre_count
)
1073 if(filenum
>= opt
->genre_count
)
1074 i
= opt
->genre_count
-1;
1078 *genre
= opt
->genre
[i
];
1079 add_tag(vc
, opt
, "genre", opt
->genre
[i
]);
1084 if(filenum
>= opt
->date_count
)
1085 i
= opt
->date_count
-1;
1089 *date
= opt
->dates
[i
];
1090 add_tag(vc
, opt
, "date", opt
->dates
[i
]);
1093 if(opt
->album_count
)
1095 if(filenum
>= opt
->album_count
)
1097 i
= opt
->album_count
-1;
1102 *album
= opt
->album
[i
];
1103 add_tag(vc
, opt
, "album", opt
->album
[i
]);
1106 if(filenum
< opt
->track_count
)
1109 *tracknum
= opt
->tracknum
[i
];
1110 add_tag(vc
, opt
, "tracknumber", opt
->tracknum
[i
]);