Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Knobs, tidal cycles-like DSL, and play-buf rename #19

Merged
merged 7 commits into from
Jun 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"github.com/jfhamlin/muscrat/pkg/conf"
"github.com/jfhamlin/muscrat/pkg/mrat"
"github.com/jfhamlin/muscrat/pkg/pubsub"
"github.com/jfhamlin/muscrat/pkg/ugen"

"github.com/wailsapp/wails/v2/pkg/runtime"
)

Expand Down Expand Up @@ -76,6 +78,24 @@ func (a *App) startup(ctx context.Context) {
}
})

pubsub.Subscribe(ugen.KnobsChangedEvent, func(event string, data any) {
// send the new knobs to the UI
go func() {
runtime.EventsEmit(ctx, "knobs-changed", ugen.GetKnobs())
}()
})

// forward knob value changes from the UI to the pubsub
runtime.EventsOn(ctx, "knob-value-change", func(data ...any) {
id := data[0].(float64)
value := data[1].(float64)
update := ugen.KnobUpdate{
ID: uint64(id),
Value: value,
}
pubsub.Publish(ugen.KnobValueChangeEvent, update)
})

pubsub.Subscribe("console.log", func(event string, data any) {
go runtime.EventsEmit(ctx, "console.log", data)
})
Expand Down Expand Up @@ -187,3 +207,7 @@ func (a *App) stopFile() {
func (a *App) GetNSPublics() []mrat.Symbol {
return mrat.GetNSPublics()
}

func (a *App) GetKnobs() []*ugen.Knob {
return ugen.GetKnobs()
}
12 changes: 10 additions & 2 deletions examples/bitcrush.glj
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
(ns user
(:require [mrat.core :refer :all]))

(def metro (impulse (knob "metro" 4 1 10)))

(def cutoff (knob "cutoff" 300 200 10000))

(play (-> (saw [100 150 202 304 606] :mul 0.5 :iphase [0.2 0 0.5])
(bitcrush :bits (step (impulse 8) [3 2 16 5]))
(rlpf 15000 :mul 0.25)
(bitcrush :bits (step metro [3 2 16 5]))
sum
(rlpf (env metro [5000 cutoff cutoff 5000] [0.01 0.01 0.1])
(- 1 (* 0.9 (env-perc metro [0.01 0.1])))
:mul 0.25)
(* 0.6)
(* (env-perc metro [0.01 0.1]))
(freeverb :room-size (knob "room-size" 0.5 0 1))
limiter))
2 changes: 1 addition & 1 deletion examples/calculating.glj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@

(play (-> (sin freq :duty (sin 4.1 :mul 0.4 :add 0.5))
(* metro)
(combc 2 0.01 3)
(combc 2 0.018 3)
(rlpf (* freq 8) 1)
(* 0.1)))
4 changes: 2 additions & 2 deletions examples/compus.glj
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@
(def trig4 (impulse (/ 1 (* 4 dur))))

(def loopr
(play-buf compus :trigger trig4 :rate (choose trig4 [0.5 1 1 1 1 2])))
(smp compus :trigger trig4 :rate (choose trig4 [0.5 1 1 1 1 2])))

(def bass
(play-buf :bass_voxy_c
(smp :bass_voxy_c
:trigger (choose trig [0 0 0 1])
:rate (choose trig [0.5 0.5 1 1 2 4])))

Expand Down
2 changes: 1 addition & 1 deletion examples/drumcircle.glj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@
(combc 2 0.014 1)
(* 0.5)
(rlpf 300 0.3)
(+ (-> (play-buf :loop_amen_full :rate (step trig [0.4 1 0.1 2 1.5 0.6 0.25]) :trigger trig :mul 0.1)
(+ (-> (smp :loop_amen_full :rate (step trig [0.4 1 0.1 2 1.5 0.6 0.25]) :trigger trig :mul 0.1)
(rhpf 1400 0.15 :mul 0.2)))
(freeverb :room-size 0.1)))
64 changes: 20 additions & 44 deletions examples/fm.glj
Original file line number Diff line number Diff line change
@@ -1,63 +1,39 @@
(ns examples.fm
(:require [mrat.core :refer :all]))

(defn fm-op
"Creates a simple FM 'operator' in the style of the Yamaha DX series."
[freq envelope input & {:keys [feedback]}]
(let [phase (phasor freq)
feedback (or feedback 0)
;; log2 is used to scale the feedback amount
;; todo: add log2 to the core namespace
feedback (math.Log2 (+ feedback 1))
has-feedback (> feedback 0)
fb (if has-feedback (pipe) 0)
osc (sin :phase (+ phase input fb)) ;; todo: sync with the trigger so that the phase is reset
out (* osc envelope)]
(if has-feedback (pipeset! fb (* feedback out)))
out))
(:use [mrat.core]))

(def impulse-rate 6)
(def gate (lfpulse impulse-rate :duty 0.2))

(def freq
(let [offset (choose gate [0 0 0 0 0 0 12 12 12 24])]
(let [offset (step gate [0 0 0 0 0 0 12 12 12 24])]
(step gate
(->> mixolydian
(map #(+ D2 % offset))
(->> locrian
(map #(+ A2 % offset))
(map mtof)))))

(def op-conf
;; freq-ratio amp adsr mod-indexes feedback carrier
[[1 0.8 [0.001 0.15 1 0.15] [1] 0.1 true]
[2 0.5 [0.001 0.15 0.1 0.15] [2] 0 false]
[7 0.3 [0.1 0.15 1 0.01] nil 0.4 false]
[2 0.5 [0.01 0.15 0.1 0.15] [2] 0.0 false]
[7 0.3 [0.01 0.15 1 0.01] nil 0.4 false]
[0.5 1 [0.1 0.15 0.5 0.001] [1 2] (knob "fb" 0 0 1) true]
])

(def fm-out
(let [ops (mapv (fn [[r a e m f c]]
(let [input (if-not (empty? m) (pipe) 0)
op (fm-op (* freq r)
(* a (env-adsr gate e))
input
:feedback f)]
{:op op
:mods m
:input input
:carrier c}))
op-conf)]
;; wire up the modulators
(doseq [{:keys [op mods input]} ops
:when (not (empty? mods))]
(let [in-sum (sum (map #(:op (nth ops %)) mods))]
(pipeset! input in-sum)))
(sum (->> ops
(filter :carrier)
(map :op)))))
(println (double (/ BUFFER-SIZE SAMPLE-RATE)))

(def trig (impulse 6))

(def kick (smp :kick :trigger (pulse-div trig 2) :mul 0.7))
(def kick-amp (amplitude kick))
(play kick)

(def sig
(-> fm-out
(combc 0.5 0.5 3)
(* 0.25)
(-> (fm-synth op-conf trig (step trig (map (comp mtof #(+ % 2)) [C3 E3 B4 E3 C3 E3 G3])))
(combc 0.5 (knob "delay" 0.25 0.1 1) 3)
(* 0.75)
tanh
(* 0.3)
(* (- 1 kick-amp))
limiter))

;; (wavout sig "fm.wav")
Expand Down
8 changes: 4 additions & 4 deletions examples/ihylp.glj
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
(ns examples.ihylpr
"A cover of 'I heard you like polyrhythms' by Virtual Riot
https://www.youtube.com/watch?v=SthcxWPXG_E"
(:require [mrat.core :refer :all]))
(:use [mrat.core]))

(def bps 1.0)

(def speed-factor 0.005)
(def speed-factor (knob "speed-factor" 0.005 0.001 0.5 0.001))

(def offset (choose (impulse (/ bps 10)) [-9 -5 0 3 7 12]))

Expand All @@ -24,7 +24,7 @@

(defn synth
[rate note]
(let [osc (sin (mtof note) :duty 0.2)
(let [osc (sin (mtof note) :duty 0.6)
trig (impulse rate :iphase (.Float64 mrand))
amp (env trig [0 1 1 0] [0.01 0.02 0.1])]
(* osc amp)))
Expand All @@ -34,6 +34,6 @@
(pan2 (/ %1 (count notes)))) (range (count notes)) notes)
(sum)
(* (/ 4 (inc (count notes))))
(freeverb :room-size 0.5)))
(freeverb :room-size (knob "room-size" 0.5 0 1))))

(play ihylpr)
19 changes: 10 additions & 9 deletions examples/karplus_strong.glj
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,26 @@

(def fade-in-time 60)

(def metro (impulse 10))
(def metro (impulse 8))

(def burst (-> (pink-noise)
(* (env-adsr metro [0.001 0.001 1 0.001]))
(def burst (-> (saw 50)
(* (env-adsr metro [0.001 0.001 1 0.1]))
(* 1)))

(def feedback (pipe))

(def delay-filter
(-> feedback
(delayc 0.5 (step metro [0.0001 0.002 0.001 0.01 0.0015 0.0019]))
(lores 1000 0)
(* (sin 4 :mul 0.02 :add 0.98))))
(lores 400 0)
(* 0.98)))

(pipeset! feedback (+ burst delay-filter))

(play (-> feedback
wfold
(loshelf 20 :db -20)
(rhpf 1200)
(hishelf 12000 :db -90)
(* 0.1)
tanh
;; (loshelf 20 :db -20)
(rlpf 500 0.2)
;; (hishelf 12000 :db -90)
limiter))
4 changes: 2 additions & 2 deletions examples/kick.glj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

(defugen kick
[trig 0]
(let [[hi lo] [700 54]
(let [[hi lo] [(knob "high-freq" 700 100 2000) 54]
freq (env-perc trig [0 0.13] :curve -6)
freq (linexp freq 0 1 lo hi)
;; another little layer
Expand All @@ -18,4 +18,4 @@
snd))


(play (kick (impulse 2) :mul 0.5))
(play (kick (impulse (knob "bps" 2 1 10)) :mul 0.5))
8 changes: 4 additions & 4 deletions examples/scriabin.glj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(ns examples.scriabin
(:require [mrat.core :refer :all] :reload
[mrat.abc :as abc] :reload))
(:require [mrat.core :refer :all]
[mrat.abc :as abc]))

(def tempo-in (midi-in "tempo" :cc :controller 70 :default 0.5))
(def tempo (* 2 72 tempo-in)) ;; 72 quarter notes per minute default
Expand Down Expand Up @@ -62,10 +62,10 @@
(def envelope-bass (mkenv metro-bass dur-bass))

(def tune
(let [sig (-> (saw (* root (semitones (sin 6 :mul 0.05))) :duty 0.8)
(let [sig (-> (saw (* root (semitones (sin 8 :mul 0.05))) :duty 0.8)
(lores (* root (semitones 7)) 0.8)
(* envelope))
sig-bass (-> (saw (* root-bass (semitones (sin 6 :mul 0.1))))
sig-bass (-> (sin (* root-bass (semitones (sin 6 :mul 0.1))) :duty 0.8)
(lores (* root-bass 3) 0.9)
(* envelope-bass))]
(-> (+ sig (* (dbamp -5) sig-bass))
Expand Down
2 changes: 1 addition & 1 deletion examples/st.glj
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
(def melody-freq-seq (env 1 [4 16 32]
[melody-cf1-time
melody-cf2-dur]
:interp :hold))
:curve :hold))

(def duty-env (env 1 [0.8 0.8 0.2 0.2] [30 2 100]))

Expand Down
18 changes: 9 additions & 9 deletions examples/sunset.glj
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
(ns examples.sunset
(:require [mrat.core :refer :all]))

(def melody-amp (* 0.3 (midi-in "melody" :cc :controller 70 :default 0.5)))
(def drone-amp (midi-in "drone" :cc :controller 74 :default 0.6))
(def amp (* 0.8 (midi-in "amp" :cc :controller 73 :default 0.5)))
(def melody-amp (* 0.3 (knob "melody" 0.5 0 1)))
(def drone-amp (knob "drone" 0.6 0 1))
(def amp (* 0.8 (knob "amp" 0.5 0 1)))

(def split-cutoff-midi (+ 40 36 (* 40 (midi-in "split" :cc :controller 71 :default 0.5))))
(def split-cutoff-midi (+ 40 36 (* 40 (knob "split" 0.5 0 1))))

(def res (* 0.95 (midi-in "res" :cc :controller 75 :default 0.6)))
(def res (* 0.95 (knob "res" 0.6 0 1)))

(def hpcutoff (mtof (+ 40 (* 90 (midi-in "hpcutoff" :cc :controller 76 :default 0)))))
(def lpcutoff (mtof (+ 20 (* 110 (midi-in "lpcutoff" :cc :controller 77 :default 1)))))
(def hpcutoff (mtof (+ 40 (* 90 (knob "hpcutoff" 0 0 1)))))
(def lpcutoff (mtof (+ 20 (* 110 (knob "lpcutoff" 1 0 1)))))

(def intervals [0 7 0 5 0 10
0 5 0 3 0 7
Expand All @@ -19,9 +19,9 @@
0 0 0 0 0 0
])

(def root-midi 50)
(def root-midi (knob "root-midi" 40 30 70 1))

(def metro (impulse 6))
(def metro (impulse (knob "metro" 4 4 6 1)))

(def metro-slo (impulse 0.1))

Expand Down
Loading
Loading