~audio-recorder/audio-recorder/trunk

« back to all changes in this revision

Viewing changes to src/timer-parser.c

  • Committer: Osmo Antero
  • Date: 2012-09-29 18:12:44 UTC
  • Revision ID: osmoma@gmail.com-20120929181244-gmrxd5xww9pua60a
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
#include "timer.h"
20
20
#include "log.h"
21
21
#include "support.h"
 
22
#include "utility.h"
22
23
#include <stdlib.h>
23
24
 
24
25
/* Parsing of timer commands:
31
32
 
32
33
 action_prep := "after" | "at" | "if" | "on"
33
34
 
34
 
 data := time | filesize | word
 
35
 data := time_notation | filesize | word
35
36
 
36
 
 time := (##:##:## | #hour #min #sec) time_suffix
 
37
 time_notation := (##:##:## | #hour #min #sec) time_suffix
37
38
 
38
39
 time_suffix := "am" | "pm" | ""
39
40
 
40
41
 filesize := # ("bytes" | "kb"|"kib" | "mb"|"mib" | "gb"|"gib" | "tb"|"tib")
41
42
 
42
 
 word := ("silence" | "voice" | "sound" | "audio") time signal_level
 
43
 word := ("silence" | "voice" | "sound" | "audio") time_notation signal_threshold
43
44
 
44
 
 signal_level := # dB | # %
 
45
 signal_threshold := #dB | #[1.1, 100]% | #[0, 1.0]
45
46
 
46
47
 Note: # means an integer or floating point number.
47
48
 Comments begin with '#' and ends at newline \n.
48
49
 
49
50
 In simplified form:
50
 
 start | stop | pause (at|after|if|on) ##:##:## (am|pm|) | ### (bytes|kb|mb|gb|tb) | (silence|voice|sound|audio) ## seconds (## dB | ## %)
 
51
 start | stop | pause (at|after|if|on) ##:##:## (am|pm|) | ### (bytes|kb|mb|gb|tb) | (silence|voice|sound|audio) ## seconds (##dB | ##% | ##)
51
52
 
52
 
 The words "voice", "sound" and "audio" mean the same thing !
 
53
 The words "voice", "sound" and "audio" has exactly same meaning!
53
54
 
54
55
 The file size units:
55
56
 https://wiki.ubuntu.com/UnitsPolicy
66
67
 stop at 08:00:30 am
67
68
 stop after 6 min 20 sec
68
69
 stop after 5 MB
69
 
 stop if silence 10 s level -20 db
70
 
 stop if silence 10 s level 10 %
 
70
 stop if silence 7 s -20 db   # duration is 7 seconds, threshold is -20dB
 
71
 stop if silence 7 s 30%  # duration is 7 seconds, threshold is 30 (=0.3)
 
72
 stop if silence 7 s 0.3  # duration is 7 seconds, threshold is 0.3 (=30%)
71
73
 stop after silence | 5GB | 35 min
72
74
 
73
75
 pause if silence 10s 7%
104
106
    gchar *translation;
105
107
} LangRec;
106
108
 
107
 
/* Notice: Timer commands are now English only.
108
 
Timer commands are not anymore translatable.
109
 
In the below structure, I have set the "translation" value to NULL.
110
 
All the functions remain the same. They should tackle the NULL value right.
111
 
 
112
 
Old definition was this:
113
 
LangRec g_transtable[] =  {
114
 
    // Translators: This is a timer command. One word only! and small letters.
115
 
    // Example: start at 10:30 pm
116
 
    {"start",   N_("start")},
117
 
 
118
 
    // Translators: This is a timer command. One word only! and small letters.
119
 
    // Example: stop after 200 kb
120
 
    {"stop",    N_("stop")},
121
 
 
122
 
    // Start/stop/pause at, after, if, on
123
 
    // Translators: This is part of timer commands. One word only! and small letters.
124
 
    // Example: start at 10:30 pm
125
 
    {"at",      N_("at")},
126
 
    ...
127
 
    ...
128
 
*/
129
 
 
130
 
// New definition is:
131
 
// The "translation" value is NULL.
132
109
LangRec g_transtable[] =  {
133
110
    // Example: start at 10:30 pm
134
111
    {"start",   NULL},
551
528
 
552
529
static void normalize_time(TimerRec *tr) {
553
530
    // Normalize decimal values to real hours/minutes/seconds
554
 
    // Eg. 2.5h means 2h 30minutes
 
531
    // Eg. 2.5h means 2h 30minutes 0seconds
555
532
 
556
533
    // Convert to 24 hours clock
557
534
    if (!g_strcmp0(tr->label, "pm") && tr->val[0] <= 12) {
581
558
 
582
559
    // State for some intricat values
583
560
    guint state = 0;
 
561
 
 
562
    gboolean seconds_set = FALSE;
 
563
    gboolean threshold_set = FALSE;
 
564
 
584
565
    while (1) {
585
566
 
586
567
        if (loop_count++ > 500) {
592
573
            break;
593
574
        }
594
575
 
595
 
        double val = 0.0;
 
576
        gdouble val = 0.0;
596
577
        gint tok_type = -1;
597
 
        // Numeric values for clock time/duration, file size or level dB
 
578
        // Numeric values for clock time/duration, file size or threshold (in dB, % or plain value [0, 1.0])
598
579
        if (g_curtoken.type == TOK_NUMERIC) {
599
580
 
600
581
            // Default data type
633
614
 
634
615
            // Next token
635
616
            parser_get_token();
 
617
 
 
618
            state = 3;
636
619
        }
637
620
 
638
621
        // Token is string/text
649
632
                tr->val[0] = val;
650
633
            }
651
634
            tr->data_type = 't';
 
635
 
 
636
            state = 3;
652
637
        }
653
638
        // filesize: bytes | kb | mb | gb | tb
654
639
        // 123 mb
680
665
            // 'd' = time duration
681
666
            tr->data_type = 'd';
682
667
            tr->val[0] = val;
 
668
            state = 3;
683
669
        } else if (match_word(g_curtoken.tok, "m", "min", "minutes", NULL)) {
684
670
            // 'd' = time duration
685
671
            tr->data_type = 'd';
686
672
            tr->val[1] = val;
 
673
            state = 3;
687
674
        } else if (match_word(g_curtoken.tok, "s", "sec", "seconds", NULL)) {
 
675
 
 
676
            if (str_length0(tr->threshold_unit) < 1) /* == '\0'*/ {
 
677
                // Save threshold value (eg. 0.4)
 
678
                // "stop if silence 0.4 5s" => "stop if silence 5s 0.4"
 
679
                tr->threshold = tr->val[2];
 
680
            }     
 
681
 
688
682
            // 'd' = time duration
689
683
            tr->data_type = 'd';
690
684
            tr->val[2] = val;
 
685
 
 
686
            state = 3;
691
687
        }
692
688
 
693
689
        // "silence"
711
707
            state = 2;
712
708
        }
713
709
 
714
 
        // Level dB (-100dB - -5dB)
 
710
        // threshold dB (-100dB - -5dB)
715
711
        else if (match_word(g_curtoken.tok, "db", "decibel", NULL)) {
716
712
            // TODO: Check if "silence", "voice" | "audio" | "sound" token detected
717
 
            g_utf8_strncpy(tr->level_unit, "db", -1);
718
 
            tr->level = val;
 
713
            g_utf8_strncpy(tr->threshold_unit, "db", -1);
 
714
            tr->threshold = val;
719
715
        }
720
716
 
721
 
        // Level % (0 - 100%)
 
717
        // Threshold % (0 - 100%)
722
718
        else if (match_word(g_curtoken.tok, "%", NULL)) {
723
 
            g_utf8_strncpy(tr->level_unit, "%", -1);
724
 
            tr->level = val;
 
719
            g_utf8_strncpy(tr->threshold_unit, "%", -1);
 
720
            tr->threshold = val;
725
721
        }
726
722
 
727
723
        // "start", "stop", "pause"
735
731
        } else {
736
732
 
737
733
            if (state == 2)  {
738
 
                // silence|voice 10 16  (take 10)
 
734
 
 
735
                // silence|voice 10 0.4  (take 10)
739
736
                if (tok_type == TOK_NUMERIC) {
740
 
                    tr->val[2] = val; // duration 10 s
 
737
                    tr->val[2] = val; // duration 10s
741
738
                }
742
739
                state = 3;
743
740
 
 
741
                seconds_set = TRUE;
 
742
 
744
743
                // Put token back
745
744
                parser_put_token_back();
746
745
 
747
746
            } else if (state == 3) {
748
 
                // silence|voice 10 16  (take 16)
 
747
 
 
748
                // silence|voice 7 30  # take 30 (=30%)
 
749
                // silence|voice 7 0.3  # take 0.3 (=30%)
749
750
                if (tok_type == TOK_NUMERIC) {
750
 
                    tr->level = val; // level 16%
751
 
                    // Default is %
752
 
                    g_utf8_strncpy(tr->level_unit, "%", -1);
 
751
                    tr->threshold = val;
 
752
                    if (tr->threshold > 1.0) {
 
753
                      // Value between [1%, 100%], assume it's a %-value
 
754
                      g_utf8_strncpy(tr->threshold_unit, "%", -1);
 
755
                    } else {
 
756
                      // Value between [0, 1.0] is a plain number
 
757
                      *(tr->threshold_unit) = '\0';
 
758
                    }
 
759
                    
753
760
                }
754
761
                state = 0;
755
762
 
 
763
                threshold_set = TRUE;
 
764
 
756
765
                // Put token back
757
766
                parser_put_token_back();
758
767
            } else if (tok_type == TOK_NUMERIC) {
781
790
        // Normalize hours/minutes/seconds. Eg. 2.5 h becomes 2 h 30 minutes.
782
791
        normalize_time(tr);
783
792
    }
 
793
 
 
794
    // start if voice 0.5 --> start if voice 0 sec 0.5  (0.5 is threshold level, not seconds!)
 
795
    if (seconds_set == TRUE && threshold_set == FALSE && tr->val[2] <= 1.00) {
 
796
        tr->threshold = tr->val[2];
 
797
        tr->val[2] = 0.0;
 
798
    }
 
799
 
784
800
}
785
801
 
786
802
static void parse_parse_line() {
824
840
        if (!g_strcmp0(g_curtoken.tok, "|") || match_word(g_curtoken.tok, "or", NULL)) {
825
841
 
826
842
            // Add new record
827
 
            parser_add_action('X'); // 'X = unknown at the moment
 
843
            parser_add_action('X'); // 'X' = unknown at the moment
828
844
 
829
845
            // Next token
830
846
            parser_get_token();
929
945
 
930
946
static void parser_fix_list() {
931
947
    // Fix OR'ed commands.
932
 
    // Eg. "stop if 100 MB | 1 h 20 min | silence" becomes three separate nodes. It becomes
 
948
    // Eg. "stop if 100 MB | 1 h 20 min | silence" becomes three separate nodes. 
 
949
    // It becomes:
933
950
    //     "stop if 100 MB"
934
951
    //     "stop if 1 h 20 min"
935
952
    //     "stop if silence"
961
978
    }
962
979
}
963
980
 
 
981
const gchar *parser_get_action_name(gchar action) {
 
982
    switch (action) {
 
983
    case 'S':
 
984
        return "Start recording";
 
985
 
 
986
    case 'c':
 
987
        return "Continue recording";
 
988
 
 
989
    case 'T':
 
990
        return "Stop recording";
 
991
 
 
992
    case 'p':
 
993
    case 'P':
 
994
        return "Pause recording";
 
995
 
 
996
    default:
 
997
        return "Unknown timer command";
 
998
    }
 
999
}
 
1000
 
964
1001
void parser_print_rec(TimerRec *tr) {
965
1002
    gchar *action_str = NULL;
966
1003
    switch (tr->action) {
988
1025
            !g_strcmp0(tr->label, "sound") ||
989
1026
            !g_strcmp0(tr->label, "audio")) {
990
1027
 
991
 
        LOG_MSG("\tlabel: %s, delay:%3.1f %3.1f %3.1f level:%3.3f %s\n", tr->label, tr->val[0], tr->val[1], tr->val[2], tr->level, tr->level_unit);
 
1028
        LOG_MSG("\tlabel: %s, delay:%3.1f %3.1f %3.1f threshold:%3.3f %s\n", tr->label, tr->val[0], tr->val[1], tr->val[2], 
 
1029
                tr->threshold, tr->threshold_unit);
992
1030
    }
993
1031
 
994
1032
    switch (tr->data_type) {