;;; transcribe.el --- Package for audio transcriptions ;; Copyright 2014-2015 Free Software Foundation, Inc. ;; Author: David Gonzalez Gandara ;; Version: 1.0.2 ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;;; Commentary: ;; REQUIRES: ;; ----------------------------- ;; This module works without any requires, but in order to use the audio ;; functions, you need to install the emacs package "emms", by Joe Drew, ;; and the external program "mpg321", by Jorgen Schafer and Ulrik Jensen, ;; both under GPL licenses. ;; ;; USAGE: ;; ------------------------- ;; Transcribe is a tool to make audio transcriptions. It allows the ;; transcriber to control the audio easily while typing, as well as ;; automate the insertion of xml tags, in case the transcription protocol ;; include them. ;; The analyse function will search for a specific structure ;; of episodes that can be automatically added with the macro NewEpisode. ;; The function expects the speech acts to be transcribed inside a turn xml ;; tag with the identifier of the speaker with optional move attribute. ;; Each speech act is spected inside a or tag, depending ;; on the language used by the person. The attributes expected are the ;; number of clauses that form the utterance, the number of errors the ;; transcriber observes, and the function of the speech act. The parser will ;; work even if some attributes are missing. ;; ;; ;; AUDIO COMMANDS ;; ------------------------------ ;; C-x C-p ------> Play audio file. You will be prompted for the name ;; of the file. The recommended format is mp2. ;; ---------> Pause or play audio. ;; C-x --> seek audio 10 seconds forward. ;; C-x --->seek audio 10 seconds backward. ;; ---------> seek interactively: positive seconds go forward and ;; negative seconds go backward ;; ;; XML TAGGING COMMANDS ;; -------------------------------------------------- ;; C-x C-n ------> Create new episode structure. This is useful in case your ;; xml file structure requires it. ;; ---------> Interactively insert a function attribute in a speech act ;; (l1 or l2) tag. ;; ---------> Interactively insert a move attribute in a turn (person) tag ;; ---------> Interactively insert an attribute (any kind) ;; ---------> Insert turn (person) tag. Inserts a move attribute. ;; --------> Insert a custom tag. Edit the function to adapt to your needs. ;; --------> Insert speech act tag in L1, with clauses, errors and function ;; attributes. ;; --------> Insert speech act tag in L2, with clauses, errors and function ;; attributes. ;; ;; AUTOMATIC PARSING ;; ----------------------------------------------------- ;; C-x C-a ------> Analyses the text for measurments of performance. ;;; Code: (if t (require 'emms-setup)) ;(require 'emms-player-mpd) ;(setq emms-player-mpd-server-name "localhost") ;(setq emms-player-mpd-server-port "6600") (emms-standard) (emms-default-players) (if t (require 'emms-player-mpg321-remote)) (defvar emms-player-list) (push 'emms-player-mpg321-remote emms-player-list) (if t (require 'emms-mode-line)) (emms-mode-line 1) (if t (require 'emms-playing-time)) (emms-playing-time 1) (defvar transcribe-function-list '("initiating" "responding" "control" "expresive" "interpersonal")) (defvar transcribe-move-list '("initiation" "response" "follow-up")) (defvar transcribe-attribute-list '("clauses" "errors" "function" "move")) ;(append transcribe-attribute-list transcribe-function-list transcribe-move-list) (defun transcribe-analyze-episode (episode person) "This calls the external python package analyze_episodes2.py. The new function transcribe-analyze implements its role now." (interactive "sepisode: \nsperson:") (shell-command (concat (expand-file-name "analyze_episodes2.py") " -e " episode " -p " person " -i " buffer-file-name ))) (defun transcribe-analyze (episodenumber personid) "Extract from a given episode and person the number of asunits per second produced, and the number of clauses per asunits, for L2 and L1." (interactive "sepisodenumber: \nspersonid:") (let* ((interventionsl2 '()) (interventionsl1 '()) (xml (xml-parse-region (point-min) (point-max))) (results (car xml)) (episodes (xml-get-children results 'episode)) (asunitsl2 0.0000) (asunitsl1 0.0000) (shifts nil) (clausesl1 0.0000) (errorsl1 0.0000) (clausesl2 0.0000) (errorsl2 0.0000) (duration nil) (number nil)) (dolist (episode episodes) (let*((numbernode (xml-get-children episode 'number))) (setq number (nth 2 (car numbernode))) (when (equal episodenumber number) (let* ((durationnode (xml-get-children episode 'duration)) (transcription (xml-get-children episode 'transcription))) (setq duration (nth 2 (car durationnode))) (dolist (turn transcription) (let* ((interventionnode (xml-get-children turn (intern personid)))) (dolist (intervention interventionnode) (let* ((l2node (xml-get-children intervention 'l2)) (l1node (xml-get-children intervention 'l1))) (dolist (l2turn l2node) (let* ((l2 (nth 2 l2turn)) (clausesl2node (nth 1 l2turn)) (clausesl2nodeinc (cdr (car clausesl2node)))) (when (not (equal clausesl2node nil)) (setq clausesl2 (+ clausesl2 (string-to-number clausesl2nodeinc)))) (when (not (equal l2 nil)) (add-to-list 'interventionsl2 l2) (setq asunitsl2 (1+ asunitsl2))))) (dolist (l1turn l1node) (let*((l1 (nth 2 l1turn)) (clausesl1node (nth 1 l1turn)) (clausesl1nodeinc (cdr (car clausesl1node)))) (when (not (equal clausesl1node nil)) (setq clausesl1 (+ clausesl1 (string-to-number clausesl1nodeinc)))) (when (not (equal l1 nil)) (add-to-list 'interventionsl1 l1) (setq asunitsl1 (1+ asunitsl1))))))))))))) (reverse interventionsl2) (reverse interventionsl1) ;(print interventions) ;uncomment to display all the interventions on screen (let((asunitspersecondl2 (/ asunitsl2 (string-to-number duration))) (clausesperasunitl2 (/ clausesl2 asunitsl2)) (asunitspersecondl1 (/ asunitsl1 (string-to-number duration))) (clausesperasunitl1 (/ clausesl1 asunitsl1))) (princ (format "episode: %s, duration: %s, person: %s\n" episodenumber duration personid)) (princ (format "L2(Asunits/second): %s, L2(clauses/Asunit): %s, L1(Asunits/second): %s" asunitspersecondl2 clausesperasunitl2 asunitspersecondl1))))) (defun transcribe-xml-tag-person (xmltag) "This function allows the automatic insetion of a speaker xml tag and places the cursor." (interactive "stag:") (insert (format "<%s move=\"\">" xmltag xmltag)) (backward-char 3) (backward-char (string-width xmltag))) (defun transcribe-xml-tag (xmltag) "This function allows the automatic insetion of a custom xml tag and places the cursor." (interactive "stag:") (insert (format "<%s>" xmltag xmltag)) (backward-char 3) (backward-char (string-width xmltag))) (defun transcribe-region-xml-tag (xmltag) "This function encapsulates the marked region in the given tag." (interactive "stag:") (let ((beginning (region-beginning)) (end (region-end))) (goto-char beginning) (insert (format "<%s>" xmltag)) (goto-char end) (insert (format "" xmltag)))) (defun transcribe-add-attribute (att val) "Adds a xml attribute at cursor with the name and value specified (autocompletion possible)" (interactive (list(completing-read "attibute name:" transcribe-attribute-list)(read-string "value:"))) (insert (format "%s=\"%s\"" att val))) (defun transcribe-add-attribute-function (val) "Adds the xml attribute 'function' at cursor with the name specified (autocompletion possible)" (interactive (list(completing-read "function name:" transcribe-function-list))) (insert (format "function=\"%s\"" val))) (defun transcribe-add-attribute-move (val) "Adds the xml attribute 'move' at cursor with the name specified (autocompletion possible" (interactive (list(completing-read "move name:" transcribe-move-list))) (insert (format "move=\"%s\"" val))) (defun transcribe-xml-tag-l1 () "Inserts a l1 tag and places the cursor" (interactive) (insert "") (backward-char 5)) (defun transcribe-xml-tag-l2 () "Inserts a l2 tag and places the cursor" (interactive) (insert "") (backward-char 5)) (defun transcribe-xml-tag-break (xmltag) "This function breaks an unit into two. That is, insert a closing and an opening equal tags" (interactive "stag:") (insert (format "<%s clauses=\"1\" errors=\"0\" function=\"\">" xmltag xmltag))) (defun transcribe-display-audio-info () (interactive) (emms-player-mpg321-remote-proc) (shell-command "/usr/bin/mpg321 -R - &")) (fset 'NewEpisode "\nDATE-NUMBER\n\n\nSubject (level)\n\n\tlow or high\nlow or high\nlow or high\r\nYes/no\n\n\n");Inserts a new episode structure ;;;###autoload (define-minor-mode transcribe-mode "Toggle transcribe-mode" nil " Trans" '(([?\C-x ?\C-p] . emms-play-file) ([?\C-x ?\C-a] . transcribe-analyze) ([?\C-x ?\C-n] . NewEpisode) ([?\C-x down] . emms-stop) ([?\C-x right] . emms-seek-forward) ([?\C-x left] . emms-seek-backward) ([f2] . transcribe-add-attribute-function) ([f3] . transcribe-add-attribute-move) ([f4] . transcribe-add-attribute) ([f5] . emms-pause) ([f8] . emms-seek) ([f9] . transcribe-xml-tag) ([f10] . transcribe-xml-tag-person) ([f11] . transcribe-xml-tag-l1) ([f12] . transcribe-xml-tag-l2)) ) (provide 'transcribe) ;;; transcribe.el ends here