回顧《禾日鑲聲》
· 4min
訊號流
這整個演出的設備工作 flow 大概是:
Strudel → OSC → SC → Pipewire → Audio Interface演出計劃
主要是因為活動偏向展覽性質,演出加上解說時間總加大約在十分鐘以內,因此採取一邊操作並解說的模式進行,畢竟 live coding 實在也沒什麼演出的規定之類的,感覺也很難介定哪邊是真正的開始或結束,只要我想達到的最終狀態有呈現出來,覺得就算是達到目標。
技術與困難
應該是從線性編曲轉向 live coding 創作有些不太習慣,當然對它還不算很熟也是個原因,抓不清楚可以達到什麼程度的表現,所幸官方的 doc 還蠻平易近人……
後來摸出一套流程可供參考:
- 先決定樂曲基本要素(調性、BPM、風格……)
- 在 DAW 試做一個「主題」(數小節的循環) 和預計加入的聲響
- 按照需求將 sample 切片 (1/4、1/8、1/16……),方便對上時間軸,也比較不會產生 pitch 改變的問題
與 hydra 的整合
在 strudel 裡可以直接把 hydra 也放進去一起使用,甚至可以直接在裡面做聲音觸發、連動 BPM 等,省去不少工具整合的麻煩。
Code
// __ __ _______ __ __ ______
// / | / |/ \ / | / | / \
// $$ | $$ |$$$$$$$ |$$ | $$ |/$$$$$$ |
// $$ |__$$ |$$ |__$$ |$$ \/$$/ $$ \__$$/
// $$ $$ |$$ $$< $$ $$< $$ \
// $$$$$$$$ |$$$$$$$ | $$$$ \ $$$$$$ |
// $$ | $$ |$$ | $$ | $$ /$$ |/ \__$$ |
// $$ | $$ |$$ | $$ |$$ | $$ |$$ $$/
// $$/ $$/ $$/ $$/ $$/ $$/ $$$$$$/
//
// HRXS Project @ 2025 by ewd
await initHydra()
setcpm(120 / 2)
let kP = "<k [~ [~ [~ k]]] k ~ k [~ [~ [~ k]]] [k [~ k] k ~] ~> / 2"
let sP = "<~ s ~ s> / 2"
let pP = "<0 2 3 4> 1 <2 0 13 2> 4 <13 0 1 2> 2"
let bt = 64
// Macro
const pMacro = register('pMacro', (degrade, jux, bin, iter, pat) => (
pat
.degradeBy(degrade)
.juxBy(jux, x => x.hurry("0.5 3 8 2.1 2.3 7 4").iter(iter))
.struct(binaryN("1000 2000 1999", bin))
.ply("<2 3 4 2> / 4")
.slow("<4 3 8 6>")
.coarse("7 | 5 | 10")
))
let colors = arrange(
[bt, s("<colors> / 64")],
[bt, s("<colors:1> / 64")],
)
let felt = arrange(
[bt / 2, s("felt / 32")],
[bt / 2, s("felt:1 / 32")]
)
// -------START HERE--------- //
//sine
// GAIN MUTE ONLY
sine: s("<~ sine ~ sine> / 4").n("0 | 1 | 2 | 3")
// .chop("16")
.striate("16")
.degrade()
.legato(1)
.often(x => x.jux(hurry(4)))
.room(0.3)
.gain(0)
// eco
_eco: s("<eco>").n(choose("0 | 1 | 2 | 3 | 4"))
.loopAt(8)
.room(0.1)
// .delay(0.4).dt(0.3)
.hpf(300)
.gain(0.8)
// swt
_swt: s("<swt> / 4").n("<1> | <2> | <3> | <4>")
// .jux(x => x.chop(4))
.hpf(600)
.gain(0.8)
// p
// pMacro(degrade[0 - 1], jux[0 - 1], bin[1 - 32], iter[1 - 4])
// "mute" not working
_p: s("p").n(pP).pMacro(0.4, 0.3, 16, 2)
.phaser("<0.5 0.2 0.3 0.5> / 4").phaserdepth("0.3")
.gain(1)
// chime
_chime: s("chime")
.n("0 | 1 | 2 | 3")
.jux(x => x.chop(4))
.degradeBy("0.7")
.legato(0.5)
.room(0.1)
.gain(0.7)
// xylo
_xylo: s("xylo")
.striate(choose("32 | 15 | 8 | 4"))
.degrade()
.sometimesBy(0.8, x => x.hurry("2").coarse(2))
.slow("<4 5 6>")
.shape(0.3)
.gain(1)
// piano colors
_colors: colors.gain(1.3)
// drum
_drum: stack(
s(kP),
s(sP)
).shape(0.2).room(0.4).delay(0.2).gain(1)
// felt piano
_felt: felt.gain(1.5)
_chord: arrange(
[bt / 2, stack(
s("chord / 32"),
s("chord:1 / 32").hpf(500).coarse(10).gain(0.3)),
],
[bt / 2, stack(
s("chord:2 / 32"),
s("chord:1 / 32").hpf(500).coarse(10).gain(0.3),
),
],
).gain(1.3)
// Hydra
osc(60, 0.05, 0.1)
.diff(osc(H("<10 5 1 5> / 4"), H("<0.1 0.2 0.1 0.4> / 4"), 0.3)
.rotate(() => time % 360 * 0.2))
.modulateScale(
// <<-
voronoi(20, 1)
// shape(10, 0.8, 0.2)
// osc(20, 0.3, 0.2)
// noise(5, 0.2)
.modulate(src(o0)
.rotate(time % 360)),
H("<0.1 0.3 0.3 0.1> / 4") // <--
)
.color(H("<1 0.9 0.8> / 8"), 0.5, 0.6, H("<0.2 0.1 0.3> / 8"))
.blend(src(o0)
.modulatePixelate(o0), H("<0.2 0.3 0.5> / 16"))
.luma(0.3, 0.5)
.invert()
// .kaleid(H("<4, 8, 12, 6> / 16"))
.blend(src(o1), 0.8) //alpha
.out(o0);