1

I have a program that plays a little snippet of music. I want it to play in a loop for a while, but I want to be able to stop it gracefully, maybe with a keypress.

(BTW I tried to avoid saying "loop" or "keypress", because I didn't want to steer the answers in that direction.)

I'm still very much a beginner with clojure, and I'm currently just running from the REPL.

  • Is it time for me to graduate to a better way to run my music function?

  • How can I tell my function to stop gracefully when I want?

sea-rob
  • 2,275
  • 1
  • 22
  • 22
  • 3
    I believe you would play your music in a [future](http://clojuredocs.org/clojure_core/clojure.core/future), that way you can [future-cancel](http://clojuredocs.org/clojure_core/clojure.core/future-cancel) to stop gracefully. – Elliott Frisch Mar 24 '14 at 14:35

2 Answers2

4

This actually depends on your actual use case: Do you want to kill the music (i.e. interrupt it while playing) or do you just want to prevent it from playing the next time?

The latter case is easily dealt with using a promise that can be filled once you think silence should fall:

(defn play-music! []
  (let [p (promise)]
    (future 
      (while (= (deref p 0 ::timeout) ::timeout)
        ...))
    #(deliver p ::stop)))

This returns a function that can be called (without arguments) to stop the loop, e.g.:

(let [stop-fn (play-music!)]
  ;; ... do important music stuff ...
  (stop-fn))

This will stop the loop after the snippet has stopped playing. If you want to really interrupt it, you can use future-cancel (but the actual result of this depends on whether your piece of music is actually interruptible):

(defn play-music! []
  (let [fut (future
              (while true
                ...))]
    #(future-cancel fut)))

This also returns the stop function. There's a variety of ways to repeatedly perform an operation, most of it are detailed e.g. here, including how to stop the resulting loop.

Community
  • 1
  • 1
xsc
  • 5,983
  • 23
  • 30
1

xsc's answer is sophisticated, informative, and probably better, but it's worth mentioning a very, very simple answer that will probably work: Run it in Leiningen, and stop the function with Ctrl-C, which I consider fairly graceful--though not perfectly graceful.

Mars
  • 8,689
  • 2
  • 42
  • 70