 ;	float - peak percent CPU usage for signal processing
 ;	double - nominal sample rate
 ;	double - actual sample rate
-(defn status []
+(defn status 
+  "Check the status of the audio server."
+  []
   (if (= @status* :booted)
     (do 
       (snd "/status")

   :replace-node 4})

;; Sending a synth-id of -1 lets the server choose an ID
(defn node [synth-name & args]
  (let [id (alloc-id :node)
        argmap (apply hash-map args)
        position ((get argmap :position :tail) POSITION)

;   int - trigger ID
;   float - trigger value

(defn notify 
  "Turn on notification messages from the audio server.  This lets us free
  synth IDs when they are automatically freed with envelope triggers.  It also lets
  us receive custom messages from various trigger ugens."
  [notify?]
  (snd "/notify" (if (false? notify?) 0 1)))

(defn- node-destroyed 
  "Frees up a synth node to keep in sync with the server."
  [id]
  (log/debug (format "node-destroyed: %d" id))
  (free-id :node id))

(defn- node-created 
  "Called when a node is created on the synth."
  [id]
  (log/debug (format "node-created: %d" id)))

(defn- register-notification-handlers 
  "Setup the feedback handlers with the audio server."
  []
  (osc-handle @server* "/n_end" #(node-destroyed (first (:args %))))
  (osc-handle @server* "/n_go" #(node-created (first (:args %)))))

(def N-RETRIES 50)

(defn- connect-thread 
  [host port]
   (log/debug "Connecting to SuperCollider server: " host ":" port)
   (dosync (ref-set server* (with-meta
                              (osc-client host port)
                              {:type ::external})))
   (loop [cnt 0]
    (when (and (< cnt N-RETRIES)
               (= @status* :booting))
      (snd "/status")
      (when (recv "status.reply" REPLY-TIMEOUT)
        (dosync (ref-set status* :booted))
        (notify true) ; turn on notifications now that we can communicate
        (run-boot-handlers))
      (recur (inc cnt))))
   (register-notification-handlers))

; TODO: setup an error-handler in the case that we can't connect to the server
(defn connect
  "Connect to an external SC audio server on the specified host and port."
  ([] (connect SERVER-HOST SERVER-PORT))
  ([host port] (.run (Thread. #(connect-thread host port)))))

(defonce running?* (atom false))

(def server-log* (ref []))

(defn server-log 
  "Print the server log."
  []
  (doseq [msg @server-log*]
    (print msg)))

