1

I'd like org-mode to reward me for completing a task by playing a nice sound when I change the state of a TODO item to DONE.

I tried two variations in my .emacs file, neither one worked. I'm on Aquamacs on OSX.

Neither of these worked:

'(org-after-todo-state-change-hook (quote (org-clock-out-if-current) (play-sound-file "~/Library/Sounds/InkSoundStroke3.aif")))

'(org-after-todo-state-change-hook (quote (org-clock-out-if-current)     (start-process-shell-command "afplay" nil "mplayer ~/Library/Sounds/InkSoundStroke3.aif")))
incandescentman
  • 6,168
  • 3
  • 46
  • 86

1 Answers1

3

Edit: if you check the docstring for the hook (C-hv org-after-todo-state-change-hook RET) you'll see that the new state is available in the variable org-state, so we can test for that:

(add-hook 'org-after-todo-state-change-hook 'my-org-after-todo-state-change)
(defun my-org-after-todo-state-change ()
  (when (string-equal org-state "DONE")
    (org-clock-out-if-current)
    (play-sound-file "~/Library/Sounds/InkSoundStroke3.aif")))
phils
  • 71,335
  • 11
  • 153
  • 198
  • Thanks. I get `Debugger entered--Lisp error: (wrong-type-argument symbolp (quote my-org-after-todo)) (defun (quote my-org-after-todo) nil (play-sound-file "~/Library/Sounds/InkSoundStroke3.aif")) eval-buffer() ; Reading at buffer position 32470 call-interactively(eval-buffer nil nil)` – incandescentman Mar 12 '13 at 00:29
  • 1
    Apologies, there was a rogue quote in there. Try it now. – phils Mar 12 '13 at 01:31
  • Clearly that is the correct solution to my original question, thank you! I'm now getting `This Emacs binary lacks sound support`, but I think that's a different problem. – incandescentman Mar 12 '13 at 04:32
  • Update: I fixed the "lacks sound support" problem using this package: https://github.com/leoliu/play-sound-osx at it works now. – incandescentman Mar 15 '13 at 17:43
  • The above plays a sound whenever a `TODO` state is changed. Is it possible to play it only when it hits `DONE`? – incandescentman Mar 15 '13 at 17:44
  • `OSX` alternative: ... `(require 'org-clock)`; `(shell-command (concat "afplay /path/to/tada.mp3"))`; `(kill-buffer "*Shell Command Output*")`; `(message "Congratulations!")`. – lawlist Jul 06 '13 at 03:38
  • Personally I have several `DONE` states, therefore, for the condition I do the more general `(member todo-state org-done-keywords)` – Michael E. Jan 19 '22 at 16:52
  • Also I'd like to add that `play-sound-file` is a blocking function, i.e. you have to wait until the sound ends before being able to do anything else. To get something non-blocking, I would use async shell commands, e.g. `(start-process-shell-command "org-done-sounds" nil (format "aplay %s" "~/Library/Sounds/InkSoundStroke3.aif"))` – Michael E. Jan 19 '22 at 17:05