Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I'm trying to mark each paragraph of transcripted text with timestamps of when/where it occurs in the audio.

mplayer and emacs are getting me close. mplayer, in the terminal, outputs a stream of suitable time info; eg. (command and sample log)

mplayer au-file 1>event.log 2>&1

A:   0.8 (00.7) of 3207.0 (53:27.0)  0.1% [J
A:   0.9 (00.9) of 3207.0 (53:27.0)  0.1% [J
A:   1.0 (01.0) of 3207.0 (53:27.0)  0.1% [J

Certain un-bound keys (eg, F12) can be used to flag an event in the log-- specifically for the start of a paragraph.

xdotool key --window $termID F12

A:   3.1 (03.0) of 3207.0 (53:27.0)  0.1% [J
No bind found for key 'F12'.                         
A:   3.2 (03.2) of 3207.0 (53:27.0)  0.1% [J
A:   3.3 (03.3) of 3207.0 (53:27.0)  0.1% [J

The above works fine. The next thing it needs is line numbers to be injected into event.log. I will probably use emacs to trigger both these events from within emacs, by binding a key to read the current point position and appending it to the log.

Yes, your guessed it, I have a problem. It seems that mplayer is keeping a stream pointer (or something?) because when it writes its next line it overwrites text I've appended. I don't know what is going on, but none of my added lines appar in the final log... I've used echo $number >>events.log.

I've watched the log via tail -f events.log and it shows one of my lines occasionally, so they must be getting there...

Is there some way around this?
Either by some fu to the log, or an entirely different method, eg. some tool which does exactly this, in real time.. I've looked at subtitling tools and audio-video editors, but they seem to be too clunky.. I'm open to any ideas.

share|improve this question
up vote 1 down vote accepted

Indeed mplayer keeps its own pointer into the file, so it does not notice when echo writes to it. When you have several programs writing to a file, arrange for all of them to open the file in append mode. In append mode, every write happens at the end of the file. From the shell, that's >>. Create an empty file with : >events.log if you want to start afresh, then run mplayer … >>events.log.

Note that while this guarantees that every byte from either program will end up in the file, there are in principle no guarantees that they won't be interspersed: in theory, echo hello >>events.log could result in h, then some mplayer output, then e, etc. appearing in the file. In practice, on most if not all systems, an echo command printing at most 512 bytes will end up in one piece.

share|improve this answer
Thanks Gilles. That has cleared up the fog. I was wondering about the caching causing anomalies... Well I've bee thinking about this (a lot), and I got to thinking that what seemed to be working against me, may need to be embraced, and I work with it... Bingo! All the lights came on! The answer is sort of obvious. It was staring me in the face and couldn't see it because of my intended solution... I read someone's comment about this syndrome just the other day..I can't remember what he called it, but it fits. Can't see the solution, because of the focus on a solution.. I'll post it... – Peter.O Nov 18 '11 at 4:07

Note. This is an asnwer to my own question

The following method works quite well. It sends a series of unbound key-presses to mplayer (mplayer logs these invalid keypresses). Each key pressed is chosen to represent one decimal digit, eg. sending F2 F5 F7 represents the decimal number 257. Sending a 6 digit number takes about 0.2 sec. The timestamp is taken from the log line just before the first (header) keypress. This avoids all problems assiciated with caching delays, as mentioned in Gilles' answer.

It can be run very easily from emacs by just moving point (cursor) to another line, or by pressing a specific key (that code is not here, but I would expect it to be simple enough (I'm new to elisp). Here is the coded and alpha-tested solution...

# Insert a number (input to this script) into mplayer's log; 
# Each digit of the input number is translated into
#   a key-press for which mplayer does not have a binding.
# mplayer makes a log entry for each invalid key-press.
# The log entry identifies the key, so the entry can be 
#   translated back into its original decimal value
# A leading and a trailing marker are also sent to mplayer
# A simple parsing of the log can rebuild the original  
#   number and the time within the media stream when it occurred.
num=${1:-123456} # Default if for testing only 
shopt -s extglob # For splitting the input number

# Window ID ($2)   Defaults to win whose title == $USER@$HOSTNAME.*
win=${2:-$(($(wmctrl -l | sed -nr "s/^([^ ]+).* $USER@$HOSTNAME.*/\1/p")))}

#    ==========  =====  ===  # Key-press translation array
#    0123456789  begin  end  # decimal digits and delimiters
key=(F12 F{1..9}   c     \') # key names
#    ==========  =====  ===  # 

xdotool key --window $win ${key[10]}    # HEAD Marker   
for i in ${num//?(.)/ } ;do
    xdotool key --window $win ${key[i]} # Encoded decimal digit
xdotool type --window $win ${key[11]}   # TAIL Marker

Here is a 3 step follow-up process to extract the timestamp and number (line number, or byte/char offset in the source text ) ...

# (1) Each line of mplayer's normal output (vs errors) ends  
#     witn `\x1B\[J\x0D`.  First, convertd this to `\n` 
sed -nr 's/\x1B\[J\x0D/\n/gp' mplayer.log  >/dev/null

# (2) The above pre-processing step(1) can be piped to the next sed step, 
#     but I've redirected it to /dev/nul for this example
#     The following step works with a few lines of the pre-processed log
nbfk="No bind found for key"
sed -nr " 
    /^$nbfk 'c'\./,/^$nbfk '''\./{
        /^$nbfk 'c'\./{g                 # HEAD Marker found 
            s/^A: *([0-9.]+).*/000000\1/
        s/^$nbfk 'F12'\..*/0/p           # Digit      
        s/^$nbfk 'F([1-9])'\..*/\1/p     # Digit
        s/^$nbfk '''\..*/--/p            # TAIL Marker found       
    h" <<'EOF'
A:  18.6 (18.6) of 3207.0 (53:27.0)  0.1% 
A:  18.7 (18.6) of 3207.0 (53:27.0)  0.1% 
No bind found for key 'c'.                         
A:  18.7 (18.6) of 3207.0 (53:27.0)  0.1% 
No bind found for key 'F1'.                         
A:  18.7 (18.7) of 3207.0 (53:27.0)  1.0% 
No bind found for key 'F2'.                         
A:  18.7 (18.7) of 3207.0 (53:27.0)  0.1% 
A:  18.8 (18.7) of 3207.0 (53:27.0)  0.1% 
No bind found for key 'F3'.                         
A:  18.8 (18.8) of 3207.0 (53:27.0)  0.1% 
No bind found for key 'F4'.                         
A:  18.8 (18.8) of 3207.0 (53:27.0)  0.1% 
No bind found for key 'F5'.                         
A:  18.9 (18.8) of 3207.0 (53:27.0)  0.1% 
No bind found for key 'F6'.                         
A:  18.9 (18.8) of 3207.0 (53:27.0)  0.1% 
No bind found for key '''.                         
A:  18.9 (18.9) of 3207.0 (53:27.0)  0.1% 
A:  19.0 (18.9) of 3207.0 (53:27.0)  0.1% 

# (3) The above step(2) can be piped to the next sed step, 
#     but I've let it go to stdout for this example
#     The following example step works with output of step (2)
sed -nr "
        /^T:[0-9.]+$/{ s/^T:(.*)/\1 /; h}
        /^--$/{g; s/\n//g; p}
    }" <<'EOF'

Here is the final output: time in seconds and the test line number

 000018.7 123456
share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.