            (when (every? zero? [size rate n-channels])
              (free-id :audio-buffer id)
              (throw (Exception. (str "Unable to read file - perhaps path is not a valid audio file: " path))))
-           (with-meta
-             (merge info
-                    {:allocated-on-server (atom true)})
-             {:type ::file-buffer}))))))
+
+           (map->BufferFile
+            (assoc info
+              :allocated-on-server (atom true))))))))
+
+(derive BufferInfo ::buffer-info)
+(derive Buffer     ::buffer)
+(derive BufferFile ::file-buffer)
 
 (derive ::buffer ::buffer-info)
 (derive ::file-buffer ::buffer)

        {:keys [start size]} arg-map
        buf (buffer-alloc-read path start size)]
    (snd "/b_read" (:id buf) path start -1 0 1)
    (with-meta
      (assoc buf
        :path path
        :start start
        :open? (atom true))
      {:type ::buffer-in-stream})))

(derive ::buffer-in-stream ::file-buffer)

(defn buffer-in-stream?

          num-samples                (* n-frames n-chans)
          rate-scale                 (/ rate (server-sample-rate))
          duration                   (/ n-frames rate)]

      (map->BufferInfo
       {:id id
        :size n-frames
        :n-channels n-chans
        :rate rate
        :n-samples num-samples
        :rate-scale rate-scale
        :duration duration}))))

(defrecord Buffer [id size n-channels rate allocated-on-server])

(defn buffer
  "Synchronously allocate a new zero filled buffer for storing audio data with
  the specified size and num-channels."
  ([size] (buffer size 1))
  ([size num-channels]
     (let [id   (with-server-self-sync
                  (fn [uid]
                    (alloc-id :audio-buffer
                              1
                              (fn [id]
                                (snd "/b_alloc" id size num-channels)
                                (server-sync uid)))))
           info (buffer-info id)]

       (map->Buffer
        (assoc info
          :allocated-on-server (atom true))))))

(defrecord BufferFile [id size n-channels rate allocated-on-server path])

(defn buffer-alloc-read
  "Synchronously allocates a buffer with the same number of channels as the
