Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ラムダ計算の拡張に基づく
音楽プログラミング言語mimium
とそのVMの実装

 ラムダ計算の拡張に基づく
音楽プログラミング言語mimium
とそのVMの実装

本発表では筆者の開発する音楽のためのプログラミング言語 mimium の理論的基盤について,音楽向け言語の歴史的文脈に沿って解説する.mimium は,リアルタイム信号処理を想定した音楽用の DSL だが,既存の多くの言語とは異なり,Unit Generator のような特定の音楽表現に基づくプリミティブを用意しない.代わりに,値呼びの単純型付きラムダ計算に遅延とフィードバックという 2 要素をプリミティブとして追加した中間表現を定義することで,その言語上でほとんどの信号処理アルゴリズムを関数のパイプとして表現できる.また,Lua を参考にした VM を設計したことで,内部状態を持つ信号処理関数の高階関数を用いた複製や,ホスト環境の埋めこみを容易に可能にしている.音楽というドメインに特化しながらも,汎用性を失わない言語の意義について議論する.

Tomoya Matsuura

January 10, 2025
Tweet

More Decks by Tomoya Matsuura

Other Decks in Research

Transcript

  1. • দӜ ஌໵ • 2019೥ະ౿ʮϓϩάϥϚϒϧͳԻָιϑτ ΢ΣΞͷ։ൃʯʢ஛ഭPMʣ • 2019~2022೥ɹ۝भେֶେֶӃ ܳज़޻ֶ෎ म࢜ɾത࢜՝ఔ

    • 2022೥͔Βɹ౦ژ᥁ज़େֶ ܳज़৘ใηϯλ ʔ(AMC) ಛ೚ॿڭ • ݚڀྖҬɿԻָ౔໦޻ֶʢCivil Engineering of Musicʣ ࣗݾ঺հ
  2. { var snare, bdrum, hihat; var tempo = 4; tempo

    = Impulse.ar(tempo); // for a drunk drummer replace Impulse with Dust !!! snare = WhiteNoise.ar(Decay2.ar(PulseDivider.ar(tempo, 4, 2), 0.005, 0.5)); bdrum = SinOsc.ar(Line.ar(120,60, 1), 0, Decay2.ar(PulseDivider.ar(tempo, 4, 0), 0.005, 0.5)); hihat = HPF.ar(WhiteNoise.ar(1), 10000) * Decay2.ar(tempo, 0.005, 0.5); Out.ar(0, (snare + bdrum + hihat) * 0.4 ! 2) }.play <CsoundSynthesizer> <CsOptions> -o dac // real-time output </CsOptions> <CsInstruments> sr = 44100 0dbfs = 1 nchnls = 2 ksmps = 64 instr 1 iAmp = p4 iFreq = p5 iAtt, iDec, iSus, iRel = 0.1, 0.4, 0.6, 0.7 kEnv = madsr:k(iAtt,iDec,iSus,iRel) iCutoff, iRes = 5000, 0.4 aVco = vco2:a(iAmp,iFreq) aLp = moogladder:a(aVco,iCutoff*kEnv,iRes) outall(aLp*kEnv) endin </CsInstruments> <CsScore> i 1 0 2 0.1 440 i 1 3 2 0.2 550 i 1 7 3 0.1 550 i 1 7 3 0.1 660 </CsScore> </CsoundSynthesizer> Cycling'74 Max CSound SuperCollider
  3. 1960 1970 1980 1990 2000 2010 2020 1950 MUSIC 1

    MUSIC 3 (UGen Language) IRCAM 4X Realtime- Variable DSP Pure Data SuperCollider ChucK Faust mimium MUSIC 5 ʢWritten in FORTRANʣ Max/FTS FORTRAN SAMSON BOX ϊϯϦΞϧλΠϜ ܭࢉػͰͷ Ի੠೾ܗੜ੒ ςΩετϑΥʔϚοτ ͰͷϓϩάϥϜهड़ ϋʔυ΢ΣΞࢧԉͰͷ ϦΞϧλΠϜ࣮ߦ ൚༻PCͰͷ ϦΞϧλΠϜ Ի੠߹੒ ݴޠͷ෼ۀԽ ؔ਺ܕϓϩάϥϛϯάͱͷ઀ଓ
  4. MUSIC-NͱUnit Generator MUSIC III(1963) by Max Mathews • ৴߸ॲཧͷجૅ୯ҐʢUnitʣΛͭͳ͍͛ͯ͘ •

    ΦγϨʔλʔ΍ϑΟϧλʔɺΤϯϕϩʔϓ • ϒϩοΫμΠΞάϥϜΛࢴʹॻ͘ˠςΩετܗࣜ ʹॻ͖௚͢ˠύϯνΧʔυʹଧͪࠐΉ • ଟ͘ͷԻָϓϩάϥϛϯάݴޠ͕͜ͷίϯηϓτ ΛҾ͖ܧ͙ • ϓϩάϥϛϯάݴޠʹݶΒͣɺWebAudio API
 ͳͲ΋UGenͷߟ͑ํΛԼෑ͖ʹ͢Δ
  5. ؔ਺ܕͷ৴߸ॲཧ Faustʢ2002~ʣ • ϒϩοΫμΠΞάϥϜ୅਺ɿೖग़ྗΛ࣋ͭϒϩοΫΛ5ͭͷԋࢉࢠͰ߹੒ • ฒྻ(,) ௚ྻ(:) ෼ذ(<:)߹ྲྀ(:>) ϑΟʔυόοΫ(~) •

    جຊϒϩοΫ: ఆ਺ / جຊ਺஋ԋࢉ / ஗Ԇ / ৚݅෼ذ* *Faustͷ৚݅෼ذ͸྆ϒϥϯνΛධՁ͔ͯ͠Β৚݅ʹ౰ͯ͸·Δ݁ՌΛऔΔ
  6. Faustͷྑ͍఺ɾѱ͍఺ • +1ͭͷίʔυ͔Βෳ਺ͷόοΫΤϯυ΁ίϯύΠϧͰ͖Δ C++/Rust/LLVM IR... • طଘͷ൚༻ݴޠͱͷཧ࿦తͳޓ׵ੑɾ૬ޓӡ༻ੑʹ͚ܽΔ • - C֎෦ؔ਺͸ϓϦϛςΟϒ஋͔Β஋΁ͷ७ਮͳࣸ૾͔͠औΕͳ͍ʢϙΠϯλ͸ڐ͞Εͳ͍ʣ

    • +- FaustΛ༷ʑͳϓϥοτϑΥʔϜʹຒΊࠐΉ͜ͱ͸Ͱ͖ͯ΋ɺFaust͔Βϗετͷؔ਺Λݺ΂ͳ͍ • BDAͱ߲ॻ͖͔͑ϚΫϩͱ͍͏2ͭͷҙຯ࿦͕ಉډ͍ͯ͠Δ • +ϚΫϩͷύλʔϯϚονʹΑͬͯෳࡶͳ৴߸ॲཧάϥϑΛදݱͰ͖Δ • - ϚΫϩͷॻ͖ํΛؒҧ͑Δͱೖग़ྗͷ਺͕Ұக͠ͳ͍BDA͕ੜ੒͞ΕΔ͕ɺΤϥʔͷݪҼ͕ಛఆͮ͠Β͍ • -ίϯύΠϧ࣌ͷఆ਺ʢ੔਺ʣͱ৴߸ॲཧͷ਺஋ܕͷ஋ͱͷ۠ผ͕Θ͔Γʹ͍͘
  7. ʢ༨ஊʣͰ͸ɺ൚༻ݴޠͰ಺෦DSLΛ࡞Δͷ͸ʁ • ϓϦΤϯϓςΟϒεέδϡʔϦϯάͳOSԼͰͷϦΞϧλΠϜॲཧͷ໰୊ • ৴߸ॲཧதʹmalloc/freeݺͿͳɺmutexϩοΫ͢Δͳ • ௿ڃݴޠ or ϩοΫϑϦʔฒߦGCͳݴޠ or

    खಈͰGCͷλΠϛϯάܾΊΒΕΔݴޠ • DSLΛ࡞Γ΍͍͢ɺࣗݾ൓өੑͷߴ͍ݴޠ΄ͲϦΞϧλΠϜॲཧͱ৯͍߹Θ͕ͤѱ͍ • 1ඵʹ48000~ճܭࢉ͢ΔͷͰ͋Δఔ౓όοϑΝʹཷΊͯ·ͱΊͯॲཧ • →࿦ཧ࣌ؒʢॱংͷΈߟྀʣͱ࣮࣌ؒʢMIDIͳͲͷೖग़ྗ࣌ʣͷ੔߹ੑͷ໰୊
  8. mimiumʹ͓͚ΔϑΟʔυόοΫͷදݱ γϯϓϧͳੵ෼ʢϩʔύεϑΟϧλʣΛྫʹ fn onepole(x,g){ x*(1.0-g) + self*g } onepole(x,g) =

    (1.0 - g) * x + g * _ ~ _; onepole(x,g) = self ~ _ with { self(y) = (1.0 - g) * x + g * y; }; mimium Faust ΋͘͠͸ (ඪ४ϥΠϒϥϦͷsi.smoothΛ୯७Խͨ͠΋ͷ) 1୯Ґ࣌ࠁલͷฦΓ஋Λऔಘ
  9. ϥϜμܭࢉϕʔεͷDSPݴޠͷઌߦྫ • Kronos[Norilo 2015] • System-FωʢܕˠܕͷϥϜμந৅͕Մೳͳߴ֊ϥϜμܭࢉͷόϦΤʔγϣϯʣΛ ϕʔεʹ͢Δ • ܕϨϕϧͷܭࢉ͕৴߸ॲཧάϥϑͷύϥϝτϦοΫͳੜ੒ʹରԠ •

    ܗࣜԽ͞Εͨҙຯ࿦ͷఏࣔ͸ͳ͠ʢιʔείʔυ͸ެ։ʣ • W-Calculus[Arias et al. 2021], CoqͰূ໌͕ຒΊࠐ·Ε͍ͯΔ • ߴ֊ؔ਺Λڐ͞ͳ͍ / ઢܗ࣌ෆมγεςϜʢΤίʔͱ͔ʣ͔͠ॻ͚ͳ͍ W-calculusͷ੍ݶΛ؇ΊͯϝϞϦ؅ཧͱ͔͸ϥϯλΠϜଆͰؤுͬͯ΋Β͏ => λmmm
  10. ຊൃදͷείʔϓ fn onepole(x,g){ x*(1.0-g) + self*g } ιʔείʔυ AST(≒λmmm) ܕਪ࿦

    ˍ MIRੜ੒ LLVM-like SSA MIR CONSTANTS:[1.0] state_size:1 fn onepole(x,g) MOVECONST 2 0 MOVE 3 1 SUBF 2 2 3 MOVE 3 0 MULF 2 2 3 GETSTATE 3 MOVE 4 1 MULF 3 3 4 ADDF 2 2 3 GETSTATE 3 SETSTATE 2 RETURN 3 1 όΠτίʔυ ੜ੒ Ծ૝ػց όΠτίʔυ φΠʔϒͳ ΠϯλϓϦλ ʢඇޮ཰ʣ 2.γϯλοΫε 3. ҙຯ࿦ 4. VM & όΠτίʔυ ͜ͷ෦෼ͷܗࣜԽ͸future work
  11. ຊൃදͷείʔϓ fn onepole(x,g){ x*(1.0-g) + self*g } ιʔείʔυ AST(≒λmmm) ܕਪ࿦

    ˍ MIRੜ੒ LLVM-like SSA MIR CONSTANTS:[1.0] state_size:1 fn onepole(x,g) MOVECONST 2 0 MOVE 3 1 SUBF 2 2 3 MOVE 3 0 MULF 2 2 3 GETSTATE 3 MOVE 4 1 MULF 3 3 4 ADDF 2 2 3 GETSTATE 3 SETSTATE 2 RETURN 3 1 όΠτίʔυ ੜ੒ Ծ૝ػց όΠτίʔυ φΠʔϒͳ ΠϯλϓϦλ ʢඇޮ཰ʣ 2.γϯλοΫε 3. ҙຯ࿦ 4. VM & όΠτίʔυ ͜ͷ෦෼ͷܗࣜԽ͸future work ׂѪ
  12. λmmm ͷγϯλοΫε (࣮ࡍʹ͸λϓϧͷΑ͏ͳ߹੒ܕ΋͋Δ͕ຊݚڀͰ͸୯७ԽͷͨΊলུʣ e ::= x x ∈ vp [value]

    | λx.e [lambda] | let x = e1 in e2 [let] | fix x.e [fixpoint] | e1 e2 [app] | if (ec ) et else ee [if ] | delay n e1 e2 n ∈ ℕ [delay] | feed x.e [feed] | ... τp ::= R [real] | N [nat] τ ::= τp | τ → τ [function] ஋ ߲ vp ::= r r ∈ ℝ | n n ∈ ℕ v ::= vp | cls(λx.e, E) ܕ
  13. ܕ෇͚نଇ(ൈਮ) Γ, x : τa ⊢ e : τb Γ

    ⊢ λx.e : τa → τb [T-LAM] Γ ⊢ n : N Γ ⊢ e1 : τ Γ ⊢ e2 : R Γ ⊢ delay n e1 e2 : τ [T-DELAY] Γ, x : τp ⊢ e : τp Γ ⊢ feedx.e : τp [T-FEED] Γ ⊢ ec : R Γ ⊢ et : τ Γ ⊢ ee : τ Γ ⊢ if (ec ) et ee : τ [T-IF] "ؔ਺ΛؚΉ͋ΒΏΔܕ͔Βܕ΁ͷࣸ૾Λڐ͢" "஗Ԇ࣌ؒΛࢦఆ͢Δ߲͸࣮਺ܕ" "৚݅෼ذͷ৚݅͸࣮਺ܕ" "Feed͸ؔ਺ΛؚΉܕΛऔΕͳ͍" "࠷େ஗Ԇ࣌ؒ͸ࣗવ਺ͷఆ਺"
  14. ܕ෇͚نଇ(ൈਮ) Γ, x : τa ⊢ e : τb Γ

    ⊢ λx.e : τa → τb [T-LAM] Γ ⊢ n : N Γ ⊢ e1 : τ Γ ⊢ e2 : R Γ ⊢ delay n e1 e2 : τ [T-DELAY] Γ, x : τp ⊢ e : τp Γ ⊢ feedx.e : τp [T-FEED] Γ ⊢ ec : R Γ ⊢ et : τ Γ ⊢ ee : τ Γ ⊢ if (ec ) et ee : τ [T-IF] ԾʹFeed͕ؔ਺ܕΛऔΔͱ͢Δͱɺ ʮ1αϯϓϧલͷؔ਺Λ࢖ͬͯ࣍ͷ࣌ࠁͷ ؔ਺Λ߹੒͢Δʯ͜ͱʹͳΔɻ →࣌ؒܦաͱͱ΋ʹ࢖༻ϝϞϦ͕૿େ ʢ㲈FRPʹ͓͚Δspace-leak໰୊ʣ
  15. λmmm ͷૢ࡞తҙຯ࿦ (Ϗοάεςοϓɺൈਮ) En ⊢ e1 ⇓ v1 n >

    v1 En−v1 ⊢ e2 ⇓ v2 En ⊢ delay n e1 e2 ⇓ v2 [E-DELAY] En ⊢ λx.e ⇓ cls(λx.e, En) [E-LAM] En−1 ⊢ e ⇓ v1 En, x ↦ v1 ⊢ e ⇓ v2 En, x ↦ v2 ⊢ feed x e ⇓ v1 [E-FEED] En ⊢ ec ⇓ n n > 0 En ⊢ et ⇓ v En ⊢ if(ec ) et else et ⇓ v [E-IFTRUE] En ⊢ ec ⇓ n n ≦ 0 En ⊢ ee ⇓ v En ⊢ if(ec ) et else et ⇓ v [E-IFFALSE] En ⊢ e1 ⇓ cls(λxc .ec , En c )En ⊢ e2 ⇓ v2 En c , xc ↦ v2 ⊢ ec ⇓ v En ⊢ e1 e2 ⇓ v [E-APP] ࣌ࠁnʹ͓͚ΔධՁ؀ڥΛ Enͱ͢Δ n<0ͷ؀ڥ͕ࢀর͞Εͨ৔߹0 Λฦ͢ɻ ͜ͷҙຯ࿦Ͱ͸ɺ࣌ࠁnͷܭࢉ ݁ՌΛಘΔͨΊʹɺ࣌ࠁ0͔Βn ·ͰͷܭࢉΛຖճ΍Γ௚͢͜ͱ ʹͳΔɻ
  16. λmmm Λ࣮ߦ͢ΔͨΊͷVMͱόΠτίʔυ • Lua VM 5.0Λݩʹઃܭ (ϨδελϚγϯ͕ͩɺϨδελ൪߸͸୯ʹίʔϧελοΫͷ૬ ରతͳҐஔΛද͢) • Ϋϩʔδϟ͕Ωϟϓνϟͨࣗ͠༝ม਺Λ

    `getupvalue`໋ྩͰ࣮ߦ࣌ʹऔಘͰ͖Δ • ͜ΕΛɺ੩తܕ෇͚ݴޠ༻ʹվม • ྫɿΫϩʔδϟͷݺͼग़͠ͱී௨ͷؔ਺ݺͼग़͠ͷ໋ྩΛ෼͚Δ • Ϋϩʔδϟ͚͕ͩώʔϓΞϩέʔτ (ݱࡏ͸ࢀরΧ΢ϯτGCͰ؅ཧ) • self ͱ delay༻ͷ಺෦ঢ়ଶૢ࡞໋ྩΛ௥Ճ
  17. MOVE A B R(A) := R(B) MOVECONST A B R(A)

    := K(B) GETUPVALUE A B R(A) := U(B) (SETUPVALUE does not exist) GETSTATE* A R(A) := SPtr[SPos] SETSTATE* A SPtr[SPos] := R(A) SHIFTSTATE* sAx SPos += sAx DELAY* A B C R(A) := update_ringbuffer(SPtr[SPos],R(B),R(C)) *(SPos,SPtr)= vm.closures[vm.statepos_stack.top()].state (if vm.statepos_stack is empty, use global state storage.) JMP sAx PC +=sAx JMPIFNEG A sBx if (R(A)<0) then PC += sBx CALL A B C R(A),...,R(A+C-2) := program.functions[R(A)](R(A+1),...,R(A+B-1)) CALLCLS A B C vm.statepos_stack.push(R(A)) R(A),...,R(A+C-2) := vm.closures[R(A)].fnproto(R(A+1),...,R(A+B-1)) vm.statepos_stack.pop() CLOSURE A Bx vm.closures.push(closure(program.functions[R(Bx)])) R(A) := vm.closures.length - 1 CLOSE A close stack variables up to R(A) RETURN A B return R(A), R(A+1)...,R(A+B-2) ADDF A B C R(A) := R(B) as float + R(C) as float SUBF A B C R(A) := R(B) as float - R(C) as float MULF A B C R(A) := R(B) as float * R(C) as float DIVF A B C R(A) := R(B) as float / R(C) as float ADDI A B C R(A) := R(B) as int + R(C) as int ...Other basic arithmetic continues for each primitive types... (࣮ࡍͷίϯύΠϥͰ͸߹੒ܕΛѻ͏ ͨΊɺଟ͘ͷ໋ྩͰϫʔυαΠζΛࣔ ͢௥ՃΦϖϥϯυ͕ಋೖ͞Ε͍ͯΔ)
  18. VMͱϓϩάϥϜͷߏ଄ͷ֓ཁ Virtual Machine Program Counter State_Ptr Stack Audio Driver Call

    Stack ... State Storage Closure Storage Base Pointer State Position State for self 1 Ring Buffer for delay 1 State for self 2 Ring Buffer for delay 2 ... Program Function Prototype0 Static Variables ... ... Function Prototype1 OP A B C OP A B C OP A B C OP A B C OP A B C Upvalue List Program State Size Local(N1) Upvalue(N2) Open Closure Function Prototype State Storage Upvalues Open(Local(N1)) Open(Upvalue(N2)) State Position Escaped Closure Function Prototype State Storage Upvalues State Position Closed Upvalue 1 Closed Upvalue 2 Somewhere on the Heap Memory (Maybe Shared with other closures)
  19. ಺෦ঢ়ଶ෇͖ؔ਺Λ࢖༻͠ͳ͍৔߹ɿ Virtual Machine Program Counter Audio Driver Call Stack ...

    Closure Storage Base Pointer Program Function Prototype0 Static Variables ... ... Function Prototype1 OP A B C OP A B C OP A B C OP A B C OP A B C Upvalue List Program Local(N1) Upvalue(N2) Open Closure Function Prototype Upvalues Open(Local(N1)) Open(Upvalue(N2)) Escaped Closure Function Prototype Upvalues Closed Upvalue 1 Closed Upvalue 2 Somewhere on the Heap Memory (Maybe Shared with other closures)
  20. ྫɿϑΟʔυόοΫ෇͖σΟϨΠΛෳ਺࢖༻͢Δ fn fbdelay(x,fb,dtime){ x + delay(1000,self,dtime)*fb } fn twodelay(x,dtime){ fbdelay(x,dtime,0.7)

    +fbdelay(x,dtime*2,0.8) } fn dsp(x){ twodelay(x,400)+twodelay(x,800) } "fbdelay" ؔ਺͸࠷େͰ1000αϯϓϧͷ delayͱ selfΛ࢖༻ "twodelay"͸"fbdelay"2ճ࢖༻ "dsp"͸"twodelay"Λ͞Βʹ2ճ࢖͏
  21. CONSTANTS:[0.7,2,0.8,400,800,0,1] fn fbdelay(x,fb,dtime) state_size:1004 MOVE 3 0 //load x GETSTATE

    4 SHIFTSTATE 1 DELAY 4 4 2 MOVE 5 1 MULF 4 4 5 ADDF 3 3 4 SHIFTSTATE -1 GETSTATE 4 SETSTATE 3 RETURN 4 1 fn twodelay(x,dtime) state_size:2008 MOVECONST 2 5 MOVE 3 0 MOVE 4 1 MOVECONST 5 0 CALL 2 3 1 SHIFTSTATE 1004 MOVECONST 3 5 MOVE 4 0 MOVECONST 5 1 //load 2 MULF 4 4 5 MOVECONST 5 0 //load 0.7 CALL 3 3 1 ADDF 3 3 4 SHIFTSTATE -1004 RETURN 3 1 fn dsp (x) state_size:4016 MOVECONST 1 6 //load twodelay MOVE 2 0 MOVECONST 3 3 //load 400 CALL 1 2 1 SHIFTSTATE 2008 MOVECONST 2 6 //load twodelay MOVE 2 3 MOVE 3 0 MOVECONST 3 4 //load 400 CALL 2 2 1 ADD 1 1 2 SHIFTSTATE -2008 RETURN 1 1 όΠτίʔυͷٙࣅίʔυදݱ
  22. fn fbdelay(x,fb,dtime) state_size:1004 MOVE 3 0 //load x GETSTATE 4

    SHIFTSTATE 1 DELAY 4 4 2 MOVE 5 1 MULF 4 4 5 ADDF 3 3 4 SHIFTSTATE -1 GETSTATE 4 SETSTATE 3 RETURN 4 1 State for Self Ring Buffer for Delay SPos ... ...
  23. fn fbdelay(x,fb,dtime) state_size:1004 MOVE 3 0 //load x GETSTATE 4

    SHIFTSTATE 1 DELAY 4 4 2 MOVE 5 1 MULF 4 4 5 ADDF 3 3 4 SHIFTSTATE -1 GETSTATE 4 SETSTATE 3 RETURN 4 1 State for Self Ring Buffer for Delay SPos "self"Λࢀর SPos͔Β1ϫʔυ෼ಡΈग़͠ɺ Ϩδελ4΁֨ೲ ... ...
  24. fn fbdelay(x,fb,dtime) state_size:1004 MOVE 3 0 //load x GETSTATE 4

    SHIFTSTATE 1 DELAY 4 4 2 MOVE 5 1 MULF 4 4 5 ADDF 3 3 4 SHIFTSTATE -1 GETSTATE 4 SETSTATE 3 RETURN 4 1 State for Self Ring Buffer for Delay SPos ... ... SPosͷҐஔΛ1ϫʔυ෼Φϑηοτ
  25. fn fbdelay(x,fb,dtime) state_size:1004 MOVE 3 0 //load x GETSTATE 4

    SHIFTSTATE 1 DELAY 4 4 2 MOVE 5 1 MULF 4 4 5 ADDF 3 3 4 SHIFTSTATE -1 GETSTATE 4 SETSTATE 3 RETURN 4 1 State for Self Ring Buffer for Delay SPos ... ... SPosͷҐஔͷϦϯάόοϑΝΛߋ৽ ೖྗ͸Ϩδελ4ɺ஗Ԇ࣌ؒ͸Ϩδελ2͔Βऔಘɺ ߋ৽ͨ͠ઌ಄ΛϨδελ4ʹॻ͖ࠐΈ
  26. fn fbdelay(x,fb,dtime) state_size:1004 MOVE 3 0 //load x GETSTATE 4

    SHIFTSTATE 1 DELAY 4 4 2 MOVE 5 1 MULF 4 4 5 ADDF 3 3 4 SHIFTSTATE -1 GETSTATE 4 SETSTATE 3 RETURN 4 1 State for Self Ring Buffer for Delay SPos ... ... SPosͷҐஔΛݩʹ໭͢ ʢؔ਺ͷίϯςΩετΛൈ͚Δ࣌ʹ͸ɺ
 ։࢝࣌ͱಉ͡Ґஔʹ໭͍ͬͯͳ͚Ε͹ͳΒͳ͍ʣ
  27. fn fbdelay(x,fb,dtime) state_size:1004 MOVE 3 0 //load x GETSTATE 4

    SHIFTSTATE 1 DELAY 4 4 2 MOVE 5 1 MULF 4 4 5 ADDF 3 3 4 SHIFTSTATE -1 GETSTATE 4 SETSTATE 3 RETURN 4 1 State for Self Ring Buffer for Delay SPos ... ... selfʹฦΓ஋Λॻ͖ࠐΉ
  28. fn twodelay(x,dtime) state_size:2008 MOVECONST 2 5 MOVE 3 0 MOVE

    4 1 MOVECONST 5 0 CALL 2 3 1 SHIFTSTATE 1004 MOVECONST 3 5 MOVE 4 0 MOVECONST 5 1 //load 2 MULF 4 4 5 MOVECONST 5 0 //load 0.7 CALL 3 3 1 ADDF 3 3 4 SHIFTSTATE -1004 RETURN 3 1 State for Self Ring Buffer for Delay SPos ... ... State for Self Ring Buffer for Delay 0 1 2 1ͭ໨ͷ"fbdelay"ݺͼग़͠
  29. fn twodelay(x,dtime) state_size:2008 MOVECONST 2 5 MOVE 3 0 MOVE

    4 1 MOVECONST 5 0 CALL 2 3 1 SHIFTSTATE 1004 MOVECONST 3 5 MOVE 4 0 MOVECONST 5 1 //load 2 MULF 4 4 5 MOVECONST 5 0 //load 0.7 CALL 3 3 1 ADDF 3 3 4 SHIFTSTATE -1004 RETURN 3 1 State for Self Ring Buffer for Delay ... ... State for Self Ring Buffer for Delay 0 1 2 SPos 3 self༻ʹ1, delay༻ʹ1000ʴಡΈग़͠Ґஔʴॻ͖ࠐΈҐஔʴαΠζ => 1004
  30. fn twodelay(x,dtime) state_size:2008 MOVECONST 2 5 MOVE 3 0 MOVE

    4 1 MOVECONST 5 0 CALL 2 3 1 SHIFTSTATE 1004 MOVECONST 3 5 MOVE 4 0 MOVECONST 5 1 //load 2 MULF 4 4 5 MOVECONST 5 0 //load 0.7 CALL 3 3 1 ADDF 3 3 4 SHIFTSTATE -1004 RETURN 3 1 State for Self Ring Buffer for Delay ... ... State for Self Ring Buffer for Delay 0 1 2 SPos 3 4 5 2ͭ໨ͷ "fbdelay"ͷݺͼग़͠
  31. fn twodelay(x,dtime) state_size:2008 MOVECONST 2 5 MOVE 3 0 MOVE

    4 1 MOVECONST 5 0 CALL 2 3 1 SHIFTSTATE 1004 MOVECONST 3 5 MOVE 4 0 MOVECONST 5 1 //load 2 MULF 4 4 5 MOVECONST 5 0 //load 0.7 CALL 3 3 1 ADDF 3 3 4 SHIFTSTATE -1004 RETURN 3 1 State for Self Ring Buffer for Delay ... ... State for Self Ring Buffer for Delay 0 1 2 SPos 3 4 5 6 SPosΛݩͷҐஔʹ໭͢
  32. fn dsp (x) state_size:4016 MOVECONST 1 6 //load twodelay MOVE

    2 0 MOVECONST 3 3 //load 400 CALL 1 2 1 SHIFTSTATE 2008 MOVECONST 2 6 //load twodelay MOVE 2 3 MOVE 3 0 MOVECONST 3 4 //load 400 CALL 2 2 1 ADD 1 1 2 SHIFTSTATE -2008 RETURN 1 1 State for Self Ring Buffer for Delay State for Self Ring Buffer for Delay 0 1 2 SPos 3 4 5 6 State for Self Ring Buffer for Delay State for Self 1ͭ໨ͷ"twodelay"ͷݺͼग़͠
  33. fn dsp (x) state_size:4016 MOVECONST 1 6 //load twodelay MOVE

    2 0 MOVECONST 3 3 //load 400 CALL 1 2 1 SHIFTSTATE 2008 MOVECONST 2 6 //load twodelay MOVE 2 3 MOVE 3 0 MOVECONST 3 4 //load 400 CALL 2 2 1 ADD 1 1 2 SHIFTSTATE -2008 RETURN 1 1 State for Self Ring Buffer for Delay State for Self Ring Buffer for Delay 0 1 2 SPos 3 4 5 6 State for Self Ring Buffer for Delay State for Self 7 2ͭ໨ͷ"twodelay"ͷݺͼग़͠
  34. fn dsp (x) state_size:4016 MOVECONST 1 6 //load twodelay MOVE

    2 0 MOVECONST 3 3 //load 400 CALL 1 2 1 SHIFTSTATE 2008 MOVECONST 2 6 //load twodelay MOVE 2 3 MOVE 3 0 MOVECONST 3 4 //load 400 CALL 2 2 1 ADD 1 1 2 SHIFTSTATE -2008 RETURN 1 1 State for Self Ring Buffer for Delay State for Self Ring Buffer for Delay 0 1 2 SPos 3 4 5 6 State for Self Ring Buffer for Delay State for Self 7 8 9 10 11 12 13 2ͭ໨ͷ"twodelay"ͷݺͼग़͠
  35. fn dsp (x) state_size:4016 MOVECONST 1 6 //load twodelay MOVE

    2 0 MOVECONST 3 3 //load 400 CALL 1 2 1 SHIFTSTATE 2008 MOVECONST 2 6 //load twodelay MOVE 2 3 MOVE 3 0 MOVECONST 3 4 //load 400 CALL 2 2 1 ADD 1 1 2 SHIFTSTATE -2008 RETURN 1 1 State for Self Ring Buffer for Delay State for Self Ring Buffer for Delay 0 1 2 SPos 3 4 5 6 State for Self Ring Buffer for Delay State for Self 7 8 9 10 11 12 13 14 SPosΛ໭͢
  36. fn dsp (x) state_size:4016 MOVECONST 1 6 //load twodelay MOVE

    2 0 MOVECONST 3 3 //load 400 CALL 1 2 1 SHIFTSTATE 2008 MOVECONST 2 6 //load twodelay MOVE 2 3 MOVE 3 0 MOVECONST 3 4 //load 400 CALL 2 2 1 ADD 1 1 2 SHIFTSTATE -2008 RETURN 1 1 State for Self Ring Buffer for Delay State for Self Ring Buffer for Delay 0 1 2 SPos 3 4 5 6 State for Self Ring Buffer for Delay State for Self 7 8 9 10 11 12 13 14 SPosͷҠಈΛ૬ରతͳΦϑηοτͰ දݱ͢ΔͷͰɺ֤ؔ਺ఆٛ͸ݺͼग़͠ ݩʹ͍ͭͯ஌Βͳͯ͘Α͍
  37. ߴ֊ؔ਺ͱ಺෦ঢ়ଶ෇͖ؔ਺ͷ૊Έ߹Θͤ fn bandpass(x,freq){ //... } fn filterbank(n,filter_factory){ if (n>0){ let

    filter = filter_factory() let next = filterbank(n-1,filter_factory) |x,freq| filter(x,freq+n*100)ɹ+ next(x,freq) }else{ |x,freq| 0 } } let myfilter = filterbank(3,| | bandpass) fn dsp(){ myfilter(x,1000) }
  38. ߴ֊ؔ਺ͱ಺෦ঢ়ଶ෇͖ؔ਺ͷ૊Έ߹Θͤ fn bandpass(x,freq){ //... } fn filterbank(n,filter_factory){ if (n>0){ let

    filter = filter_factory() let next = filterbank(n-1,filter_factory) |x,freq| filter(x,freq+n*100)ɹ+ next(x,freq) }else{ |x,freq| 0 } } let myfilter = filterbank(3,| | bandpass) fn dsp(){ myfilter(x,1000) } Ҿ਺ͱͯ͠༩͑ΒΕΔ fi lter_factoryͷ಺෦ঢ়ଶαΠζ͸ ίϯύΠϧ࣌ʹ֬ఆͰ͖ͳ͍
  39. Virtual Machine Program Counter State_Ptr Stack Audio Driver Call Stack

    ... State Storage Closure Storage Base Pointer State Position State for self 1 Ring Buffer for delay 1 State for self 2 Ring Buffer for delay 2 ... Program Function Prototype0 Static Variables ... ... Function Prototype1 OP A B C OP A B C OP A B C OP A B C OP A B C Upvalue List Program State Size Local(N1) Upvalue(N2) Open Closure Function Prototype State Storage Upvalues Open(Local(N1)) Open(Upvalue(N2)) State Position Escaped Closure Function Prototype State Storage Upvalues State Position Closed Upvalue 1 Closed Upvalue 2 Somewhere on the Heap Memory (Maybe Shared with other closures) $-0463&໋ྩʹΑͬͯΫϩʔδϟ͕ΠϯελϯεԽ͞ΕΔ࣌ɺ Ϋϩʔδϟ্ʹ಺෦ঢ়ଶετϨʔδΛผ్֬อ͢Δ
  40. Virtual Machine Program Counter State_Ptr Stack Audio Driver Call Stack

    ... State Storage Closure Storage Base Pointer State Position State for self 1 Ring Buffer for delay 1 State for self 2 Ring Buffer for delay 2 ... Program Function Prototype0 Static Variables ... ... Function Prototype1 OP A B C OP A B C OP A B C OP A B C OP A B C Upvalue List Program State Size Local(N1) Upvalue(N2) Open Closure Function Prototype State Storage Upvalues Open(Local(N1)) Open(Upvalue(N2)) State Position Escaped Closure Function Prototype State Storage Upvalues State Position Closed Upvalue 1 Closed Upvalue 2 Somewhere on the Heap Memory (Maybe Shared with other closures) CALLCLS ໋ྩͰΫϩʔδϟΛݺͼग़͢ͱ͖ɺGET/SET/SHIFTSTATE/DELAY໋ྩͰ ࢖༻͢Δ಺෦ঢ়ଶετϨʔδͷϙΠϯλΛઐ༻ͷελοΫʹੵΜͰ੾Γସ͑Δ
  41. CONSTANTS[100,1,0,2] fn inner_then(x,freq) //upvalue: [local(4),local(3),local(2),local(1)] GETUPVALUE 3 2 //load filter

    MOVE 4 0 MOVE 5 1 GETUPVALUE 6 1 //load n ADDD 5 5 6 MOVECONST 6 0 MULF 5 5 6 CALLCLS 3 2 1 //call filter GETUPVALUE 4 4 //load next MOVE 5 0 MOVE 6 1 CALLCLS 4 2 1 //call next ADDF 3 3 4 RETURN 3 1 fn inner_else(x,freq) MOVECONST 2 2 RETURN 2 1 fn filterbank(n,filter_factory) MOVE 2 0 //load n MOVECONST 3 2 //load 0 SUBF 2 2 3 JMPIFNEG 2 12 MOVE 2 1 //load filter_factory CALL 2 2 0 //get filter MOVECONST 3 1 //load itself MOVE 4 0 //load n MOVECONST 5 1 //load 1 SUBF 4 4 5 MOVECONST 5 2 //load inner_then CALLCLS 3 2 1 //recursive call MOVECONST 4 2 //load inner_then CLOSURE 4 4 //load inner_lambda JMP 2 MOVECONST 4 3 //load inner_else CLOSURE 4 4 CLOSE 4 RETURN 4 1 "GET/SET/SHIFTSTATE/DELAY"͸Ҿ਺ͱͯ͠౉͞ΕΔ fi lter_factoryͷதͰ ͚ͩݺ͹Εͯɺ fi lterbankؔ਺Ͱ͸࢖༻͞Ε͍ͯͳ͍
  42. ߴ֊ؔ਺ͱ಺෦ঢ়ଶ෇͖ؔ਺ͷ૊Έ߹Θͤ fn bandpass(x,freq){ //... } fn filterbank(n,filter_factory:()->(float,float)->float){ if (n>0){ let

    filter = filter_factory() let next = filterbank(n-1,filter_factory) |x,freq| filter(x,freq+n*100) + next(x,freq) }else{ |x,freq| 0 } } let myfilter = filterbank(3,| | bandpass) fn dsp(){ myfilter(x,1000) } ݁ہɺΦϒδΣΫτࢦ޲ϓϩάϥϛϯάʹ͓͚Δ Unit GeneratorͷίϯετϥΫλʹ૬౰͢Δ
  43. ଞݴޠͱͷൺֱ ύϥϝτϦοΫͳ
 ৴߸ॲཧάϥϑͷੜ੒ ࣮ࡍͷDSP Faust ߲ॻ͖͔͑ϚΫϩ ϒϩοΫμΠΞάϥϜ୆਺ Kronos ܕϨϕϧܭࢉ ஋Ϩϕϧܭࢉ

    mimium άϩʔόϧ؀ڥͷ஋ධՁ dsp ؔ਺ͷධՁ mimiumͰ͸ͲͪΒ΋ಉ͡ҙຯ࿦Ͱ஋ϨϕϧͷධՁɻ 
 ͜Ε͸ॳֶऀʹͱͬͯΘ͔Γ΍͍͢ͱ΋ݴ͑Δ͕ɺҰํͰ...
  44. ಈ͔ͳ͍ίʔυͷྫ fn filterbank(n,filter){ if (n>0){ |x,freq| filter(x,freq+n*100) + filterbank(n-1,filter)(x,freq) }else{

    |x,freq| 0 } } fn dsp(){ filterbank(3,bandpass)(x,1000) } ͜ͷॻ͖ํͩͱɺΫϩʔδϟ͕ຖ࣌ࠁੜ੒͞Εɺ ಺෦ঢ়ଶ͕ຖ࣌ࠁϦηοτ͞Εͯ͠·͏
  45. ଟஈ֊ܭࢉΛಋೖͰ͖ͨ৔߹ɿ fn filterbank(n,filter:&(float,float)->float)->&(float,float)->float{ .< if (n>0){ |x,freq| ~filter(x,freq+n*100) + ~filterbank(n-1,filter)(x,freq)

    }else{ |x,freq| 0 } >. } fn dsp(){ ~filterbank(3,.<bandpass>.)(x,1000) } *BER MetaOCamlͬΆ͍γϯλοΫεΛ࠾༻ͨ͠૝ఆͷٙࣅίʔυ
  46. fn gen_sampler_mono(machine: &mut Machine) -> ReturnCode { let abspath =

    {...}; let vec = load_wavfile_to_vec(abspath.to_str().unwrap()) .inspect_err(|e| { panic!("gen_sampler_mono error: {}", e); }) .unwrap(); //ಡΈࠐ·ΕͨԻ੠഑ྻ͸࣍ͷΫϩʔδϟͰΩϟϓνϟɺϜʔϒ͞ΕΔ let res = move |machine: &mut Machine| -> ReturnCode { let pos = vm::Machine::get_as::<f64>(machine.get_stack(0)); let val = interpolate_vec(&vec, pos); machine.set_stack(0, Machine::to_value(val)); 1 }; let ty = function!(vec![numeric!()], numeric!()); //mimium্ͷܕγάωνϟ let idx = machine.wrap_extern_cls(("sampler_mono".to_symbol(), ɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹRc::new(RefCell::new(res)), ty)); machine.set_stack(0, Machine::to_value(idx)); 1 } Rust্Ͱ͸LuaͰͷόΠϯσΟϯάͷΑ͏ʹɺVMͷίʔϧελοΫ౳Λ௚઀ૢ࡞
  47. fn gen_sampler_mono(machine: &mut Machine) -> ReturnCode { //return higher order

    closure let abspath = { ... }; let vec = load_wavfile_to_vec(abspath.to_str().unwrap()) .inspect_err(|e| { panic!("gen_sampler_mono error: {}", e); }) .unwrap(); //the generated vector is moved into the closure let res = move |machine: &mut Machine| -> ReturnCode { let pos = vm::Machine::get_as::<f64>(machine.get_stack(0)); let val = interpolate_vec(&vec, pos); machine.set_stack(0, Machine::to_value(val)); 1 }; let ty = function!(vec![numeric!()], numeric!()); //mimium্ͷܕγάωνϟ let idx = machine.wrap_extern_cls(("sampler_mono".to_symbol(), Rc::new(RefCell::new(res)), ty)); machine.set_stack(0, Machine::to_value(idx)); 1 } Rust্Ͱ͸LuaͷόΠϯσΟϯάͷΑ͏ʹɺVMͷίʔϧελοΫ౳Λ௚઀ૢ࡞
  48. impl Plugin for SamplerPlugin { fn get_ext_functions(&self) -> Vec<vm::ExtFnInfo> {

    let t = function!(vec![string_t!()], function!(vec![numeric!()], numeric!())); let sig = ( "gen_sampler_mono".to_symbol(), gen_sampler_mono as ExtFunType, t, ); vec![sig] } } PluginτϨΠτΛ௨ͯ͡mimium͔Βݺͼग़ͨ͢Ίͷ໊લͱܕ৘ใɺ࣮ࡍʹݺͼग़͞ΕΔؔ਺ΛΤΫεϙʔτ ʢࠓޙ͸खଓ͖ϚΫϩͰόΠϯσΟϯάੜ੒ΛࣗಈԽ͍ͨ͠ʣ
  49. ·ͱΊ • λmmm: ஋ݺͼ୯७ܕ෇͖ϥϜμܭࢉσΟϨΠͱϑΟʔυόοΫΛ௥Ճͨ͠ମܥ • ͦΕΛ࣮ߦ͢ΔͨΊͷVMͱ໋ྩηοτͷઃܭ • GET/SET/SHIFTSTATE/DELAYͰσΟϨΠͱϑΟʔυόοΫΛऔΓѻ͏ • ߴ֊ؔ਺Ͱ಺෦ঢ়ଶΛऔΓѻ͏ͨΊʹɺΫϩʔδϟͷΠϯελϯε͕಺෦ঢ়ଶετϨʔδΛ࣋ͭ

    • ύϥϝτϦοΫͳ৴߸ॲཧੜ੒ͱɺ࣮ࡍͷॲཧͷ࣮ߦΛಉ͡ҙຯ࿦Ͱ࣮ߦͰ͖Δ • ҙຯ࿦Λֶश͠΍͘͢͸͋Δ͕ɺϢʔβʔ͸ίʔυ͕άϩʔόϧධՁͱDSPධՁͲͪΒͰߦΘΕ Δ͔Λ஫ҙ͠ͳ͚Ε͹ͳΒͳ͍ • Իָͱ͍͏υϝΠϯʹಛԽͯ͠͸͍Δ͕ɺ൚༻ੑɺࣗݾ֦ுੑɺ૬ޓӡ༻ੑΛอͬͨݴޠ