add timings conversion and rework offsets master
authorNiki Roo <niki@nikiroo.be>
Sat, 6 Jul 2024 14:21:41 +0000 (16:21 +0200)
committerNiki Roo <niki@nikiroo.be>
Sat, 6 Jul 2024 14:21:41 +0000 (16:21 +0200)
src/nsub/nsub.c
src/nsub/nsub.h
src/nsub/nsub_main.c
src/nsub/nsub_read_lrc.c
src/nsub/nsub_read_srt.c
src/nsub/nsub_write_lrc.c
src/nsub/nsub_write_srt.c
src/nsub/nsub_write_webvtt.c

index bab09de4281b74c035c7d24170c676c129fffb62..f23e94255285f5e12f59280e476347c9b6425e42 100644 (file)
@@ -158,14 +158,18 @@ song_t *nsub_read(FILE *in, NSUB_FORMAT fmt) {
        return song;
 }
 
-int nsub_write(FILE *out, song_t *song, NSUB_FORMAT fmt, int apply_offset) {
+int nsub_write(FILE *out, song_t *song, NSUB_FORMAT fmt, int apply_offset,
+               int add_offset, double conv) {
        switch (fmt) {
        case NSUB_FMT_LRC:
-               return nsub_write_lrc(out, song, fmt, apply_offset);
+               return nsub_write_lrc(out, song, fmt, apply_offset, 
+                       add_offset, conv);
        case NSUB_FMT_WEBVTT:
-               return nsub_write_webvtt(out, song, fmt, apply_offset);
+               return nsub_write_webvtt(out, song, fmt, apply_offset, 
+                       add_offset, conv);
        case NSUB_FMT_SRT:
-               return nsub_write_srt(out, song, fmt, apply_offset);
+               return nsub_write_srt(out, song, fmt, apply_offset, 
+                       add_offset, conv);
        default:
                fprintf(stderr, "Unsupported write format %d\n", fmt);
                return 0;
@@ -268,3 +272,14 @@ int nsub_is_timing(const char line[], char deci_sym, int max_deci) {
 
        return 1;
 }
+
+int apply_conv(int time, double conv) {
+       // Just so we don't require -lm...
+       double tmp = time * conv;
+       double diff = tmp - (int)tmp;
+       
+       if (diff >= 0.5)
+               return (int)tmp + 1;
+       return (int)tmp;
+}
+
index 35bf3346b2d62c3beb8c85793b24bd62015ab37e..611f667a3367e67931c1d03f3d17c38ce9db7faa 100644 (file)
@@ -181,6 +181,16 @@ int nsub_to_ms(const char line[], char deci_sym);
  */
 int nsub_is_timing(const char line[], char deci_sym, int max_deci);
 
+/**
+ * Apply a conversion ratio to the given time.
+ *
+ * @param time the initial time to compute from
+ * @param conv the conversion ratio to apply (i.e., 1 = no conversion)
+ *
+ * @return the converted time
+ */
+int apply_conv(int time, double conv);
+
 song_t *nsub_read(FILE *in, NSUB_FORMAT fmt);
 int nsub_read_lrc(song_t *song, char *line);
 int nsub_read_webvtt(song_t *song, char *line);
@@ -188,10 +198,14 @@ int nsub_read_srt(song_t *song, char *line);
 
 /* Write */
 
-int nsub_write(FILE *out, song_t *song, NSUB_FORMAT fmt, int apply_offset);
-int nsub_write_lrc(FILE *out, song_t *song, NSUB_FORMAT fmt, int apply_offset);
+// conv = time conversion ratio
+int nsub_write(FILE *out, song_t *song, NSUB_FORMAT fmt, int apply_offset,
+               int add_offset, double conv);
+int nsub_write_lrc(FILE *out, song_t *song, NSUB_FORMAT fmt, int apply_offset,
+               int add_offset, double conv);
 int nsub_write_webvtt(FILE *out, song_t *song, NSUB_FORMAT fmt,
-               int apply_offset);
-int nsub_write_srt(FILE *out, song_t *song, NSUB_FORMAT fmt, int apply_offset);
+               int apply_offset, int add_offset, double conv);
+int nsub_write_srt(FILE *out, song_t *song, NSUB_FORMAT fmt, int apply_offset,
+               int add_offset, double conv);
 
 #endif /* NSUB_H */
index c11e8b6b46f9605928abea9c8b43f01b629a2bd5..7878e341043fa9a41f7ea400bc27ac3e8c59a7e4 100644 (file)
@@ -35,6 +35,8 @@ int main(int argc, char **argv) {
        char *in_file = NULL;
        char *out_file = NULL;
        int apply_offset = 0;
+       int add_offset = 0;
+       double conv = 1;
 
        if (argc <= 1) {
                help(argv[0]);
@@ -49,30 +51,84 @@ int main(int argc, char **argv) {
                } else if (!strcmp("--from", arg) || !strcmp("-f", arg)) {
                        if (i + 1 >= argc) {
                                fprintf(stderr,
-                                               "The parameter --from/-f requires an argument\n");
+                                       "The parameter --from/-f "
+                                       "requires an argument\n"
+                               );
                                return 5;
                        }
                        from = nsub_parse_fmt(argv[++i], 1);
                        if (from == NSUB_FMT_ERROR) {
-                               fprintf(stderr, "Unsupported input format: %s\n", argv[i]);
+                               fprintf(stderr, 
+                                       "Unsupported input "
+                                       "format: %s\n", argv[i]
+                               );
                                return 8;
                        }
                } else if (!strcmp("--to", arg) || !strcmp("-t", arg)) {
                        if (i + 1 >= argc) {
-                               fprintf(stderr, "The parameter --to/-t requires an argument\n");
+                               fprintf(stderr, 
+                                       "The parameter --to/-t "
+                                       "requires an argument\n"
+                               );
                                return 5;
                        }
                        to = nsub_parse_fmt(argv[++i], 1);
                        if (to == NSUB_FMT_ERROR) {
-                               fprintf(stderr, "Unsupported output format: %s\n", argv[i]);
+                               fprintf(stderr, 
+                                       "Unsupported output "
+                                       "format: %s\n", argv[i]
+                               );
                                return 9;
                        }
-               } else if (!strcmp("--apply-offset", arg) || !strcmp("-a", arg)) {
+               } else if (!strcmp("--apply-offset", arg) 
+                               || !strcmp("-a", arg)) {
                        apply_offset = 1;
+               } else if (!strcmp("--ntsc", arg) 
+                               || !strcmp("-n", arg)) {
+                       conv = 25.00 / 29.97;
+               } else if (!strcmp("--pal", arg) 
+                               || !strcmp("-p", arg)) {
+                       conv = 29.97 / 25.00;
+               } else if (!strcmp("--offset", arg) 
+                               || !strcmp("-o", arg)) {
+                       if (i + 1 >= argc) {
+                               fprintf(stderr,
+                                       "The parameter --offset/-o requires "
+                                       "an argument\n"
+                               );
+                               return 5;
+                       }
+
+                       if (sscanf(argv[++i], "%i", &add_offset) == EOF) {
+                               fprintf(stderr, 
+                                       "Bad parameter to %s: %s\n",
+                                       arg, argv[i-1]
+                               );
+                               return 5;
+                       }
+               } else if (!strcmp("--ratio", arg) 
+                               || !strcmp("-r", arg)) {
+                       if (i + 1 >= argc) {
+                               fprintf(stderr,
+                                       "The parameter --ratio/-r requires "
+                                       "an argument\n"
+                               );
+                               return 5;
+                       }
+
+                       if (sscanf(argv[++i], "%lf", &conv) == EOF) {
+                               fprintf(stderr, 
+                                       "Bad parameter to %s: %s\n",
+                                       arg, argv[i-1]
+                               );
+                               return 5;
+                       }
                } else if (!strcmp("--output", arg) || !strcmp("-o", arg)) {
                        if (i + 1 >= argc) {
                                fprintf(stderr,
-                                               "The parameter --output/-o requires an argument\n");
+                                       "The parameter --output/-o requires "
+                                       "an argument\n"
+                               );
                                return 5;
                        }
                        out_file = argv[++i];
@@ -109,13 +165,17 @@ int main(int argc, char **argv) {
 
        if (from == NSUB_FMT_UNKNOWN) {
                fprintf(stderr,
-                               "Cannot detect input format, please specify it with '--from'\n");
+                       "Cannot detect input format, "
+                       "please specify it with '--from'\n"
+               );
                return 6;
        }
 
        if (to == NSUB_FMT_UNKNOWN) {
                fprintf(stderr,
-                               "Cannot detect output format, please specify it with '--to'\n");
+                       "Cannot detect output format, "
+                       "please specify it with '--to'\n"
+               );
                return 7;
        }
 
@@ -123,7 +183,9 @@ int main(int argc, char **argv) {
        if (in_file && !(in_file[0] == '-' && !in_file[1])) {
                in = fopen(in_file, "r");
                if (!in) {
-                       fprintf(stderr, "Cannot open input file: %s\n", in_file);
+                       fprintf(stderr, 
+                               "Cannot open input file: %s\n", in_file
+                       );
                        rep = 2;
                }
        }
@@ -132,7 +194,9 @@ int main(int argc, char **argv) {
        if (!rep && out_file && !(out_file[0] == '-' && !out_file[1])) {
                out = fopen(out_file, "w");
                if (!in) {
-                       fprintf(stderr, "Cannot create output file: %s\n", out_file);
+                       fprintf(stderr, 
+                               "Cannot create output file: %s\n", out_file
+                       );
                        rep = 3;
                }
        }
@@ -142,7 +206,8 @@ int main(int argc, char **argv) {
                if (!song)
                        rep = 22;
 
-               if (!rep && !nsub_write(out, song, to, apply_offset))
+               if (!rep && !nsub_write(out, song, to, apply_offset, 
+                               add_offset, conv))
                        rep = 33;
 
                free_song(song);
@@ -179,25 +244,51 @@ NSUB_FORMAT nsub_parse_fmt(char *type, int required) {
 void help(char *program) {
        printf("NSub subtitles conversion program\n");
        printf("Syntax:\n");
-       printf("\t%s (--from FMT) (--to FMT) (--apply-offset)\n"
-                       "\t\t (--output OUT_FILE) (IN_FILE)\n", program);
-       printf("\t> --help (or -h): this help message\n");
-       printf("\t> --from (or -f) FMT: select the input format FMT\n");
-       printf("\t> --to (or -t) FMT: select the output format FMT\n");
+       printf("\t%s (--from FMT) (--to FMT) (--apply-offset) (--offset MSEC)\n"
+                       "\t\t (--ntsc) (--pal) (--ratio RATIO)\n"
+                       "\t\t (--output OUT_FILE) (IN_FILE)\n", 
+               program
+       );
+       
+       printf("\nOptions:\n");
+       printf("\t-h/--help         : this help message\n");
+       printf("\t-f/--from FMT     : select the input  format FMT\n");
+       printf("\t-t/--to   FMT     : select the output format FMT\n");
+       printf("\t-a/--apply-offset : apply the offset tag "
+               "value to the lyrics\n"
+       );
+       printf("\t-o/--offset MSEC  : add a manual offset to all timings\n");
+       printf("\t-n/--ntsc         : Convert timings from NTSC to PAL\n");
+       printf("\t-p/--pal          : Convert timings from PAL to NTSC\n");
+       printf("\t-r/--ratio RATIO  : Convert timings with a "
+               "custom ratio\n");
+       
+       printf("\nArguments:\n");
        printf(
-                       "\t> --apply-offset (or -a): apply the offset tag value to the lyrics\n");
+               "\tIN_FILE  : the input file or '-' for stdin "
+               "(which is the default)\n"
+       );
        printf(
-                       "\t> IN_FILE: the input file or '-' for stdin (which is the default)\n");
+               "\tOUT_FILE : the output file or '-' for stdout "
+               "(which is the default)\n"
+       );
+       printf("\tRATIO    : the ratio to apply to timings (1 = no change)\n");
        printf(
-                       "\t> OUT_FILE: the output file or '-' for stdout (which is the default)\n");
+               "\tMSEC     : the offset to add to all timings in "
+               "milliseconds\n"
+       );
        printf("\n");
        printf(
-                       "Note: the in/out formats will be guessed from the extension if needed/possible\n");
+               "Note: the in/out formats will be guessed from the "
+               "extension if needed/possible\n"
+       );
        printf(
-                       "Note: to specify a file named dash (-), prefix it with a path (e.g., './-')\n");
+               "Note: to specify a file named dash (-), prefix it with a path"
+               " (e.g., './-')\n"
+       );
        printf("\n");
        printf("Supported formats:\n");
-       printf("\tlrc: lyrics files\n");
-       printf("\tsrt: SubRip subtitles files\n");
-       printf("\tvtt/webvtt: Web Video Text Tracks\n");
+       printf("\tlrc: lyrics files\n");
+       printf("\tsrt: SubRip subtitles files\n");
+       printf("\tvtt/webvtt: Web Video Text Tracks\n");
 }
index 7e56a259d9bcd3b9ce71f0b36bfc0bae4ebae832..9ce858e0eb654a059124b2797f06708d1106325d 100644 (file)
@@ -122,12 +122,14 @@ static int is_lrc_offset(char *line) {
        if (*offset)
                return 0;
 
-       // skip spaces then ':'
+       // skip spaces then ':', then spaces
        while (*line == ' ')
                line++;
        if (*line && *line != ':')
                return 0;
        line++;
+       while (*line == ' ')
+               line++;
 
        // allow sign
        if (*line == '-' || *line == '+')
@@ -217,6 +219,7 @@ static int lrc_millisec(char *line) {
                // skip [offset:
                while (*line != ':')
                        line++;
+               line++;
                while (*line == ' ')
                        line++;
 
@@ -232,8 +235,9 @@ static int lrc_millisec(char *line) {
        } else {
                /* should not happen! */
                fprintf(stderr,
-                               "Warning: called lrc_millisec with bad input [%s], ignoring...\n",
-                               line);
+                       "Warning: called lrc_millisec with bad input"
+                       " [%s], ignoring...\n",
+               line);
                return 0;
        }
 
index c19bc9f91d4fad31137435fc6d975b43aaf8b91c..894c342f05bf2179e5d3db22eb98c792f6cfd022 100644 (file)
@@ -46,8 +46,10 @@ int nsub_read_srt(song_t *song, char *line) {
                int new_count = atoi(line);
                if (new_count != count + 1) {
                        fprintf(stderr,
-                                       "Warning: line %zu is out of order (it is numbered %i), ignoring order...\n",
-                                       count, new_count);
+                               "Warning: line %zu is out of order "
+                               "(it is numbered %i), ignoring order...\n",
+                               count, new_count
+                       );
                }
 
                song_add_lyric(song, 0, 0, NULL, NULL);
@@ -164,8 +166,10 @@ static int get_start(char *line) {
        if (!is_srt_timing(line)) {
                /* should not happen! */
                fprintf(stderr,
-                               "Warning: called get_start with bad input [%s], ignoring...\n",
-                               line);
+                       "Warning: called get_start with bad input "
+                       "[%s], ignoring...\n",
+                       line
+               );
                return 0;
        }
 
@@ -190,8 +194,10 @@ static int get_stop(char *line) {
        if (!is_srt_timing(line)) {
                /* should not happen! */
                fprintf(stderr,
-                               "Warning: called get_stop with bad input [%s], ignoring...\n",
-                               line);
+                       "Warning: called get_stop with bad input "
+                       "[%s], ignoring...\n",
+                       line
+               );
                return 0;
        }
 
index 1d42815c10abdad066e8a1732f8b8a0dd4ecbdcc..4575679bdae99094fa78f5ce520ce4502552184f 100644 (file)
 /* Declarations */
 
 char *nsub_lrc_time_str(int time, int show_sign);
-void nsub_write_lrc_lyric(FILE *out, lyric_t *lyric, int offset);
+void nsub_write_lrc_lyric(FILE *out, lyric_t *lyric, int offset, double conv);
 
 /* Public */
 
-int nsub_write_lrc(FILE *out, song_t *song, NSUB_FORMAT fmt, int apply_offset) {
-       int offset;
+int nsub_write_lrc(FILE *out, song_t *song, NSUB_FORMAT fmt, int apply_offset,
+               int add_offset, double conv) {
+       int offset = add_offset;
 
        // header: none
 
@@ -44,10 +45,9 @@ int nsub_write_lrc(FILE *out, song_t *song, NSUB_FORMAT fmt, int apply_offset) {
        {
                char *offset_str;
                if (apply_offset) {
-                       offset = song->offset;
+                       offset += song->offset;
                        offset_str = nsub_lrc_time_str(0, 1);
                } else {
-                       offset = 0;
                        offset_str = nsub_lrc_time_str(song->offset, 1);
                }
                fprintf(out, "[offset: %s]\n", offset_str);
@@ -64,7 +64,7 @@ int nsub_write_lrc(FILE *out, song_t *song, NSUB_FORMAT fmt, int apply_offset) {
        // lyrics
        array_loop(song->lyrics, lyric, lyric_t)
        {
-               nsub_write_lrc_lyric(out, lyric, offset);
+               nsub_write_lrc_lyric(out, lyric, offset, conv);
        }
 
        return 1;
@@ -72,19 +72,11 @@ int nsub_write_lrc(FILE *out, song_t *song, NSUB_FORMAT fmt, int apply_offset) {
 
 /* Private */
 
-void nsub_write_lrc_lyric(FILE *out, lyric_t *lyric, int offset) {
+void nsub_write_lrc_lyric(FILE *out, lyric_t *lyric, int offset, double conv) {
        static int lrc_last_stop = 0;
 
        if (lyric->type == NSUB_EMPTY) {
-               if (lrc_last_stop) {
-                       char *time = nsub_lrc_time_str(lrc_last_stop, 0);
-                       fprintf(out, "[%s]\n", time);
-                       free(time);
-               } else {
-                       fprintf(out, "\n");
-               }
-
-               lrc_last_stop = 0;
+               fprintf(out, "\n");
                return;
        }
 
@@ -95,11 +87,20 @@ void nsub_write_lrc_lyric(FILE *out, lyric_t *lyric, int offset) {
                }
 
                fprintf(out, "-- %s\n", tmp->string);
-               lrc_last_stop = 0;
 
                free_cstring(tmp);
                return;
        }
+       
+       int start_time = apply_conv(lyric->start, conv) + offset;
+       if (lrc_last_stop && lrc_last_stop != start_time) {
+               char *time = nsub_lrc_time_str(lrc_last_stop, 0);
+               fprintf(out, "[%s]\n", time);
+               fprintf(out, "\n");
+               free(time);
+               lrc_last_stop = 0;
+       }
+       
 
        if (lyric->name) {
                cstring_t *tmp = cstring_clone(lyric->name);
@@ -111,8 +112,8 @@ void nsub_write_lrc_lyric(FILE *out, lyric_t *lyric, int offset) {
 
                free_cstring(tmp);
        }
-
-       char *time = nsub_lrc_time_str(lyric->start + offset, 0);
+       
+       char *time = nsub_lrc_time_str(start_time, 0);
        cstring_t *tmp = cstring_clone(lyric->text);
        if (tmp) {
                cstring_replace(tmp, "\n", "\\n");
@@ -121,7 +122,7 @@ void nsub_write_lrc_lyric(FILE *out, lyric_t *lyric, int offset) {
        free(time);
        free_cstring(tmp);
 
-       lrc_last_stop = lyric->stop + offset;
+       lrc_last_stop = apply_conv(lyric->stop, conv) + offset;
 }
 
 char *nsub_lrc_time_str(int time, int show_sign) {
index 2ecaa25960091b9a8fabddfeca9b179362b96dbb..4357f7053d4c05b9c6f2248b22f3a79e1f748ada 100644 (file)
 /* Declarations */
 
 char *nsub_srt_time_str(int time, int show_sign);
-void nsub_write_srt_lyric(FILE *out, lyric_t *lyric, int offset);
+void nsub_write_srt_lyric(FILE *out, lyric_t *lyric, int offset, double conv);
 
 /* Public */
 
-int nsub_write_srt(FILE *out, song_t *song, NSUB_FORMAT fmt, int apply_offset) {
-       int offset;
+int nsub_write_srt(FILE *out, song_t *song, NSUB_FORMAT fmt, int apply_offset,
+               int add_offset, double conv) {
+       int offset = add_offset;
 
        // header: none
 
@@ -38,7 +39,7 @@ int nsub_write_srt(FILE *out, song_t *song, NSUB_FORMAT fmt, int apply_offset) {
 
        // offset is not supported in SRT (so, always applied)
        {
-               offset = song->offset;
+               offset += song->offset;
        }
 
        // other metas: none
@@ -46,7 +47,7 @@ int nsub_write_srt(FILE *out, song_t *song, NSUB_FORMAT fmt, int apply_offset) {
        // lyrics
        array_loop(song->lyrics, lyric, lyric_t)
        {
-               nsub_write_srt_lyric(out, lyric, offset);
+               nsub_write_srt_lyric(out, lyric, offset, conv);
        }
 
        return 1;
@@ -54,7 +55,7 @@ int nsub_write_srt(FILE *out, song_t *song, NSUB_FORMAT fmt, int apply_offset) {
 
 /* Private */
 
-void nsub_write_srt_lyric(FILE *out, lyric_t *lyric, int offset) {
+void nsub_write_srt_lyric(FILE *out, lyric_t *lyric, int offset, double conv) {
        if (lyric->type == NSUB_EMPTY) {
                // not supported, ignored
                return;
@@ -71,8 +72,12 @@ void nsub_write_srt_lyric(FILE *out, lyric_t *lyric, int offset) {
        //if (lyric->name)
        // not supported, ignored
 
-       char *start = nsub_srt_time_str(lyric->start + offset, 0);
-       char *stop = nsub_srt_time_str(lyric->stop + offset, 0);
+       char *start = nsub_srt_time_str(
+               apply_conv(lyric->start, conv) + offset, 
+       0);
+       char *stop = nsub_srt_time_str(
+               apply_conv(lyric->stop , conv) + offset, 
+       0);
        fprintf(out, "%s --> %s\n%s\n\n", start, stop, lyric->text);
        free(start);
        free(stop);
index 761bc463883dcfee7db10407c9dc43eeb1b200fc..370506a630ed195fecd4228525f7e3ba0251429f 100644 (file)
 /* Declarations */
 
 char *nsub_webvtt_time_str(int time, int show_sign);
-void nsub_write_webvtt_lyric(FILE *out, lyric_t *lyric, int offset);
+void nsub_write_webvtt_lyric(FILE *out, lyric_t *lyric, int offset, 
+               double conv);
 
 /* Public */
 
 int nsub_write_webvtt(FILE *out, song_t *song, NSUB_FORMAT fmt,
-               int apply_offset) {
-       int offset;
+               int apply_offset, int add_offset, double conv) {
+       int offset = add_offset;
 
        // header
        {
@@ -49,7 +50,7 @@ int nsub_write_webvtt(FILE *out, song_t *song, NSUB_FORMAT fmt,
 
        // offset is not supported in WebVTT (so, always applied)
        {
-               offset = song->offset;
+               offset += song->offset;
        }
 
        // other metas
@@ -62,7 +63,7 @@ int nsub_write_webvtt(FILE *out, song_t *song, NSUB_FORMAT fmt,
        // lyrics
        array_loop(song->lyrics, lyric, lyric_t)
        {
-               nsub_write_webvtt_lyric(out, lyric, offset);
+               nsub_write_webvtt_lyric(out, lyric, offset, conv);
        }
 
        return 1;
@@ -70,7 +71,8 @@ int nsub_write_webvtt(FILE *out, song_t *song, NSUB_FORMAT fmt,
 
 /* Private */
 
-void nsub_write_webvtt_lyric(FILE *out, lyric_t *lyric, int offset) {
+void nsub_write_webvtt_lyric(FILE *out, lyric_t *lyric, int offset, 
+               double conv) {
        if (lyric->type == NSUB_EMPTY) {
                fprintf(out, "\n\n");
                return;
@@ -87,9 +89,13 @@ void nsub_write_webvtt_lyric(FILE *out, lyric_t *lyric, int offset) {
        // Not always supported by clients, so disabled:
        // if (lyric->name)
        //fprintf(out, "%s\n", lyric->name);
-
-       char *start = nsub_webvtt_time_str(lyric->start + offset, 0);
-       char *stop = nsub_webvtt_time_str(lyric->stop + offset, 0);
+       
+       char *start = nsub_webvtt_time_str(
+               apply_conv(lyric->start, conv) + offset, 
+       0);
+       char *stop = nsub_webvtt_time_str(
+               apply_conv(lyric->stop , conv) + offset, 
+       0);
        fprintf(out, "%s --> %s\n%s\n\n", start, stop, lyric->text);
        free(start);
        free(stop);