Skip to content

Commit

Permalink
java9 compatability, move bytespec and midi-clj to the overtone-tree,…
Browse files Browse the repository at this point in the history
… catch some reflection warnings with typehints
  • Loading branch information
hlolli committed May 9, 2019
1 parent dc48585 commit 79b671a
Show file tree
Hide file tree
Showing 39 changed files with 1,362 additions and 231 deletions.
36 changes: 17 additions & 19 deletions project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,27 @@
`leiningen.core.eval/get-os` for that system. Temporarily disabled
options can be kept under `:disabled`."
{:any
["-Xms512m" "-Xmx1g" ; Minimum and maximum sizes of the heap
"-XX:+UseConcMarkSweepGC" ; Use concurrent garbage collector
"-XX:+CMSConcurrentMTEnabled" ; Enable multi-threaded concurrent gc work (ParNewGC)
"-XX:MaxGCPauseMillis=20" ; Specify a target of 20ms for max gc pauses
"-XX:MaxNewSize=257m" ; Specify the max and min size of the new
"-XX:NewSize=256m" ; generation to be small
"-XX:+UseTLAB" ; Uses thread-local object allocation blocks. This
["-Xms512m" "-Xmx1g" ; Minimum and maximum sizes of the heap
"-XX:+CMSConcurrentMTEnabled" ; Enable multi-threaded concurrent gc work (ParNewGC)
"-XX:MaxGCPauseMillis=20" ; Specify a target of 20ms for max gc pauses
"-XX:MaxNewSize=257m" ; Specify the max and min size of the new
"-XX:NewSize=256m" ; generation to be small
"-XX:+UseTLAB" ; Uses thread-local object allocation blocks. This
; improves concurrency by reducing contention on
; the shared heap lock.
"-XX:MaxTenuringThreshold=0"] ; Makes the full NewSize available to every NewGC
"-XX:MaxTenuringThreshold=0"] ; Makes the full NewSize available to every NewGC
; cycle, and reduces the pause time by not
; evaluating tenured objects. Technically, this
; setting promotes all live objects to the older
; generation, rather than copying them.
:disabled
["-XX:ConcGCThreads=2" ; Use 2 threads with concurrent gc collections
"-XX:TieredCompilation" ; JVM7 - combine both client and server compilation
["-XX:ConcGCThreads=2" ; Use 2 threads with concurrent gc collections
"-XX:TieredCompilation" ; JVM7 - combine both client and server compilation
; strategies
"-XX:CompileThreshold=1" ; JIT each function after one execution
"-XX:+PrintGC" ; Print GC info to stdout
"-XX:+PrintGCDetails" ; - with details
"-XX:+PrintGCTimeStamps"]}) ; - and timestamps
"-XX:CompileThreshold=1" ; JIT each function after one execution
"-XX:+PrintGC" ; Print GC info to stdout
"-XX:+PrintGCDetails" ; - with details
"-XX:+PrintGCTimeStamps"]}) ; - and timestamps

(defn jvm-opts
"Return a complete vector of jvm-opts for the current os."
Expand All @@ -46,19 +45,18 @@
:distribution :repo
:comments "Please use Overtone for good"}

:dependencies [[org.clojure/clojure "1.9.0"]
:dependencies [[org.clojure/clojure "1.10.0"]
[org.clojure/data.json "0.2.6"]
[clj-native "0.9.5"]
[overtone/at-at "1.2.0"]
[overtone/osc-clj "0.9.0"]
[overtone/byte-spec "0.3.1"]
[overtone/midi-clj "0.5.0"]
[overtone/libs.handlers "0.2.0"]
[overtone/ableton-link "1.0.0-beta1"]
[clj-glob "1.0.0"]
[net.java.dev.jna/jna "4.4.0"]
[overtone/scsynth "3.9.3-1"]
[overtone/scsynth-extras "3.9.3-1"]]
[overtone/scsynth "3.10.2"]
[overtone/scsynth-extras "3.10.2"]
]
:profiles {:test {:dependencies [[bultitude "0.2.0"]
[polynome "0.2.2"]]}}
:test-selectors {:core (fn [m] (not (some m [:gui :hw])))
Expand Down
3 changes: 1 addition & 2 deletions src/overtone/api.clj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(ns overtone.api
(:import [java.lang.management ManagementFactory])
(:use [overtone.libs boot-msg app-icon]
(:use [overtone.libs boot-msg]
[overtone.helpers.ns])
(:require clojure.stacktrace
[overtone.config store]
Expand Down Expand Up @@ -111,4 +111,3 @@
'overtone.libs.event
'overtone.samples.freesound
'overtone.version))

205 changes: 205 additions & 0 deletions src/overtone/byte_spec.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
(ns overtone.byte-spec
(:import (java.net URL)
(java.io FileInputStream FileOutputStream
DataInputStream DataOutputStream
BufferedInputStream BufferedOutputStream
ByteArrayOutputStream ByteArrayInputStream)))

;; This file implements a DSL for specifying the layout of binary data formats.
;; Look at synthdef.clj that defines the format for SuperCollider
;; synthesizer definition (.scsyndef) files for an example of usage.

(def ^{:dynamic true} *spec-out* nil)
(def ^{:dynamic true} *spec-in* nil)

(defn- bytes-to-int [bytes]
(-> bytes (ByteArrayInputStream.) (DataInputStream.) (.readInt)))

(defn- read-pstring []
(let [len (.readByte ^DataInputStream *spec-in*)
bytes (byte-array len)]
(.readFully ^DataInputStream *spec-in* bytes)
(String. bytes)))

(defn- write-pstring [^java.lang.String s]
(.writeByte ^DataOutputStream *spec-out* (count s))
(.write ^DataOutputStream *spec-out* (.getBytes s)))

;; Standard numeric types + Pascal style strings.
;; pstring => a byte giving the string length followed by the ascii bytes
(def READERS {
:int8 #(.readByte ^DataInputStream *spec-in*)
:int16 #(.readShort ^DataInputStream *spec-in*)
:int32 #(.readInt ^DataInputStream *spec-in*)
:int64 #(.readLong ^DataInputStream *spec-in*)
:float32 #(.readFloat ^DataInputStream *spec-in*)
:float64 #(.readDouble ^DataInputStream *spec-in*)

:byte #(.readByte ^DataInputStream *spec-in*)
:short #(.readShort ^DataInputStream *spec-in*)
:int #(.readInt ^DataInputStream *spec-in*)
:long #(.readLong ^DataInputStream *spec-in*)
:float #(.readFloat ^DataInputStream *spec-in*)
:double #(.readDouble ^DataInputStream *spec-in*)

:string read-pstring
})

(def WRITERS {
:int8 #(.writeByte ^DataOutputStream *spec-out* %1)
:int16 #(.writeShort ^DataOutputStream *spec-out* %1)
:int32 #(.writeInt ^DataOutputStream *spec-out* %1)
:int64 #(.writeLong ^DataOutputStream *spec-out* %1)
:float32 #(.writeFloat ^DataOutputStream *spec-out* %1)
:float64 #(.writeDouble ^DataOutputStream *spec-out* %1)

:byte #(.writeByte ^DataOutputStream *spec-out* %1)
:short #(.writeShort ^DataOutputStream *spec-out* %1)
:int #(.writeInt ^DataOutputStream *spec-out* %1)
:long #(.writeLong ^DataOutputStream *spec-out* %1)
:float #(.writeFloat ^DataOutputStream *spec-out* %1)
:double #(.writeDouble ^DataOutputStream *spec-out* %1)

:string write-pstring
})

;; TODO: Make this complete
;; For now it just does enough to handle SuperCollider oddity
(defn- coerce-default [value ftype]
(if (and (string? value) (= :int32 ftype))
(bytes-to-int (.getBytes ^java.lang.String value))
value))

(defn make-spec [spec-name field-specs]
(loop [specs field-specs
fields []]
(if specs
(let [fname (first specs)
ftype (second specs)
fdefault (if (and (> (count specs) 2)
(not (keyword? (nth specs 2))))
(nth specs 2)
nil)
fdefault (coerce-default fdefault ftype)
spec {:fname fname
:ftype ftype
:fdefault fdefault}
specs (if (nil? fdefault)
(next (next specs))
(next (next (next specs))))
fields (conj fields spec)]
;(println (str "field: " spec))
(recur specs fields))
{:name (str spec-name)
:specs fields})))

;; A spec is just a hash-map containing a named vector of field specs
(defmacro defspec [spec-name & field-specs]
`(def ~spec-name (make-spec ~(str spec-name) [~@field-specs])))

(defn spec [s & data]
(let [field-names (map #(:fname %1) (:specs s))]
(apply hash-map (interleave field-names data))))

(declare spec-read)

(defn- spec-read-array [spec size]
(loop [i size
ary []]
(if (pos? i)
(let [next-val (if (contains? READERS spec)
((spec READERS))
(spec-read spec))]
(recur (dec i) (conj ary next-val)))
ary)))

(defn spec-read
"Returns an instantiation of the provided spec, with data read from
a DataInputStream bound to *spec-in*."
[spec]
(loop [specs (:specs spec)
data {}]
(if specs
(let [{:keys [fname ftype fdefault]} (first specs)
fval (cond
;; basic type
(contains? READERS ftype) ((ftype READERS))

;; sub-spec
(map? ftype) (spec-read ftype)

;; array
(vector? ftype) (spec-read-array (first ftype)
((keyword (str "n-" (name fname))) data)))]
(recur (next specs) (assoc data fname fval)))
data)))

(defn spec-read-bytes [spec bytes]
(binding [*spec-in* (-> bytes (ByteArrayInputStream.) (BufferedInputStream.) (DataInputStream.))]
(spec-read spec)))

(defn spec-read-url [spec ^java.net.URL url]
(with-open [ins (.openStream url)]
(binding [*spec-in* (-> ins (BufferedInputStream.) (DataInputStream.))]
(spec-read spec))))

(declare spec-write)

(defn- spec-write-array [spec ary]
;(println (str "WRITE-A: [ "
; (if (map? spec) (:name spec) spec) " ](" (count ary) ")"))
;(println "ary: " ary)
(let [nxt-writer (cond
(contains? WRITERS spec) (spec WRITERS)
(map? spec) (partial spec-write spec)
true (throw (IllegalArgumentException.
(str "Invalid spec: " spec))))]
(doseq [item ary]
(nxt-writer item))))

(defn spec-write-basic [ftype fname fval fdefault]
(if-let [val (or fval fdefault)]
((ftype WRITERS) val)
(throw (Exception. (str "No value was given for '" fname "' field and it has no default.")))))

(defn count-for [fname]
(keyword (.substring (name fname) 2)))

(defn spec-write
"Serializes the data according to spec, writing bytes onto *spec-out*."
[spec data]
(doseq [{:keys [fname ftype fdefault]} (:specs spec)]
(cond
; count of another field starting with n-
(.startsWith (name fname) "n-")
(let [wrt (ftype WRITERS)
c-field (get data (count-for fname))
cnt (count c-field)]
(wrt cnt))

; an array of sub-specs
(vector? ftype) (spec-write-array (first ftype) (fname data))

; a single sub-spec
(map? ftype) (spec-write ftype (fname data))

; a basic type
(contains? WRITERS ftype) (spec-write-basic ftype fname (fname data) fdefault)

true (throw (IllegalArgumentException.
(str "Invalid field spec: " fname " " ftype))))))

(defn spec-write-file [spec data ^java.lang.String path]
(with-open [spec-out (-> path (FileOutputStream.) (BufferedOutputStream.) (DataOutputStream.))]
(binding [*spec-out* spec-out]
(spec-write spec data))))

(defn spec-write-bytes [spec data]
(let [bos (ByteArrayOutputStream.)]
(with-open [out (DataOutputStream. bos)]
(binding [*spec-out* out]
(spec-write spec data)))
(.toByteArray bos)))

(defn bytes-and-back [spec obj]
(spec-read-bytes spec (spec-write-bytes spec obj)))
2 changes: 1 addition & 1 deletion src/overtone/helpers/audio_file.clj
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
n-bytes (* data-size sample-bytes)
b-data (ByteBuffer/allocate n-bytes)
b-data (fill-data-buffer! b-data data sample-bytes)
stream (AudioInputStream. (ByteArrayInputStream. (.array b-data))
stream (AudioInputStream. (ByteArrayInputStream. (.array ^ByteBuffer b-data))
a-format
data-size)
f (file path)
Expand Down

0 comments on commit 79b671a

Please sign in to comment.