メインコンテンツまでスキップ

作業ログ:5月上旬

· 約3分

MIDIトリガー メモプラグイン

一旦完成

スクリーンショット01

友達が欲しいと言っていたので、MIDIトリガー機能のあるメモプラグインを作っていました。

WebView周りに色々苦戦し、結局一か月くらい掛かったな、、、

zustandを使っていい感じに、JUCEとの連携が出来るProviderが出来たので、記事にしてまとめたいな、、、

フロントエンド部分だけだけど、核となる部分のコードはだいたいこんな感じ、

providers/juce.tsx
import { getNativeFunction } from 'juce-framework-frontend-mirror'
import { createContext, PropsWithChildren, useCallback, useContext, useEffect, useRef, useState } from 'react'
import { createStore, useStore } from 'zustand'

type SharedState = {
someState: string
// ...
}

type FrontendState = {
modalIsOpen: boolean
}

type State = SharedState & FrontendState

type Action = {
undo: () => void
redo: () => void

setSomeState: (v: string) => void
setModalIsOpen: (v: boolean) => void // only frontend
}

type JuceStore = ReturnType<typeof createJuceStore>

const createJuceStore = (initProps: Partial<State>) => {
const loadState = getNativeFunction('loadState')
const changeState = getNativeFunction('changeState')
const undo = getNativeFunction('undo')
const redo = getNativeFunction('redo')

const load = async () => {
return {
someState: await loadState('someState'),
}
}

const DEFAULT_STATES: State = {
someState: 'midi',
modalIsOpen: false,
canUndo: false,
canRedo: false,
}

return createStore<State & Action>()((set) => ({
...DEFAULT_STATES,
...initProps,
undo: () => {
undo().then(() => {
load().then((states) => {
set(() => states)
})
})
},
redo: () => {
redo().then(() => {
load().then((states) => {
set(() => states)
})
})
},
setSomeState: (v) =>
set(() => {
changeState('someState', v)
return { someState: v }
}),
setModalIsOpen: (v) => set(() => ({ modalIsOpen: v })),
}))
}

const JuceContext = createContext<JuceStore | null>(null)

type JuceProviderProps = PropsWithChildren<Partial<State>>

/** remove undefined in object. */
function cleanObject<T extends object>(obj: T): Partial<T> {
return Object.fromEntries(
Object.entries(obj).filter(([, v]) => v != undefined)
) as Partial<T>
}

export function JuceProvider({ children, ...props }: JuceProviderProps) {
const storeRef = useRef<JuceStore>(null)
const [savedStates, setSavedStates] = useState<Partial<State>>({})

const loadInitialData = useCallback(() => {
const data = window.__JUCE__.initialisationData
return cleanObject<SharedState>({
someState: data.someState?.[0],
})
}, [])


if (!storeRef.current) {
const initials = loadInitialData()
storeRef.current = createJuceStore({...savedStates, ...initials, ...props})
}

useEffect(() => {
if (storeRef.current) {
storeRef.current.setState({...savedStates, ...props})
} else {
const initials = loadInitialData()
storeRef.current = createJuceStore({...savedStates, ...initials, ...props})
}
}, [loadInitialData, props, savedStates])

useEffect(() => {
const onChangeCanUndoOrRedoId = window.__JUCE__.backend.addEventListener(
'onChangeCanUndoOrRedo',
([canUndo, canRedo]) => {
setSavedStates({...savedStates, canUndo, canRedo})
}
)

return () => {
window.__JUCE__.backend.removeEventListener(onChangeCanUndoOrRedoId)
}
}, [savedStates])

return (
<JuceContext.Provider value={storeRef.current}>
{children}
</JuceContext.Provider>
)
}

export function useJuceContext<T>(selector: (state: State & Action) => T): T {
const store = useContext(JuceContext)
if (!store) throw new Error('Missing JuceContext.Provider in the tree')
return useStore(store, selector)
}

undo, redoは、juceのUndoManagerに任せて、フロントで状態を更新するというような仕様となっている

作業ログ:4月19日

· 約1分

MIDIトリガー メモプラグイン

JUCEのUIを @tremolo-ui/react で作る

· 約8分

JUCEAdvent Calendar 2024

3日目

この記事は、JUCE Advent Calendar 2024 の3日目の記事です。

はじめに

3日目の mimoz です。色々忙しく、かなり遅れてしまいました。すいません。

この記事では、私が現在開発しているオーディオ・アプリケーション向けのUIライブラリ tremolo-ui を使い、JUCEのUIを作成していきます。

実は、この記事の執筆に合わせて、ライブラリの配信の準備を進めていたのですが、JavaScriptバンドラー周りが上手く行かず、サンプルがだいぶ質素な見た目になってしまいました。

モチベーション

まず、このライブラリを作り始めた経緯をお話しします。

プラグイン等のオーディオ・アプリケーションのUIは、既存の汎用的なUIライブラリではカバー出来ない部分がありました。代表的なもので言えば、Rotary Knob (回転ノブ)や、鍵盤などです。

また、既存のライブラリによくある Slider などでも、対数的な表示 (skew) を実装するのが大変だったりしました。

そこで現在開発しているのが、tremolo-ui です

https://github.com/m1m0zzz/tremolo-ui

tremolo-ui では以下のことを目標としています。

  • 使いやすさと拡張性
    → ヘッドレスUIライク・特殊なUIイベントのためのコンポーネント等
  • モバイルサポート
    → クロスプラットフォームであるJUCEと共に使用することを考慮し、モバイルでも単一のコードで動くこと

juce-framework-frontend-mirror の紹介

· 約4分

JUCEAdvent Calendar 2024

2日目

この記事は、JUCE Advent Calendar 2024 の2日目の記事です。

はじめに

作曲や、開発をしている mimoz と申します。 普段は、Web系のプログラムを書くことが多いですが、今年の4月頃からJUCEでVSTプラグインの制作を始めました。

JUCE8にてWebViewが本格的にサポートされました

ライブラリの紹介の前に、WebViewの話を少ししようと思います。

JUCEにWebViewが搭載されたことで、HTML・CSS・JavaScript、そしてReactなどのフレームワークが使用でき、簡単にUIの構築が可能になります。(もちろんJavaScriptやその他のフレームワークを学習するコストはあると思いますが...)

また、これまでは、数ピクセルの変更を行う度にコンパイルしていましたが、ホットリロードを使用すれば、コンパイル無しで、変更が画面へと反映されます。

他にも有利な点など、詳しく紹介されています。こちらの公式ブログを参照してください。
JUCE 8 Feature Overview: WebView UIs

AbletonのOverdriveが無難に良い

· 約1分

overdrive

みなさんは、Ableton Liveの付属のエフェクトであるOverdriveを使っているだろうか?

至って普通のディストーションかもしれないが、使い勝手が良いし、Live標準のエフェクトなので動作も軽い。

パラメーターは、

preフィルター (バンドパス) セクション, Drive, Tone (postフィルター), Dynamics, Dry/Wet

という構成。

特に、[Dynamics] スライダーが良くて、Dynamicsを上げると、歪みが目立つようになり、逆に小さい値のときには、少ない歪みで音を太くさせるような印象があります。

特に生楽器系には、Dynamicsを小さめに、ベースやリードには大きめの値で使っていることが多い

X-Yコントローラーのフィルターセクションも直感的で使いやすい。

Utility clone を支える技術 ~DSP編~

· 約9分

はじめに

先日、Utility cloneというVSTプラグインをリリースしました。

Utility cloneはAbleton LiveのUtilityという標準のエフェクトを模して作ったプラグインです。

Utilityは、ゲインやパンなど、よく使用する処理がまとめられたエフェクトで、
自分のプロジェクトファイルには冗談抜きで全トラックに挿さっています。それくらい必須のエフェクトです。

今回制作した Utility clone は、JUCEというフレームワークを使用していて、Windows, Mac, Linuxに対応しています。
また、コードはGitHubで公開しています。ダウンロードもこちらからできます。

https://github.com/m1m0zzz/utility-clone

Ableton リンク集(随時更新)

· 約2分

Liveユーザーでない方でも!

Learning Music - Ableton
https://learningmusic.ableton.com/ja/

Learning Synths - Ableton
https://learningsynths.ableton.com/ja/

ブラウザ上で、手を動かしながら作曲やシンセサイザーを学べるサイトです。
普通に楽しい

Ableton Japan 公式YouTubeチャンネル

https://youtube.com/@AbletonJapan

Ableton Live一口メモ シリーズで、Ableton LiveのテクニックやM4Lなどが紹介されています。

「ぼくの考えた最強のデフォルトLiveセット」を作ろう

· 約3分

Liveセットとは

他のDAWで言うところの、テンプレートのこと。
デフォルトのLiveセットを設定することで、DAWを開いた時のトラックやルーティングをカスタマイズすることができる。

Liveセットをデフォルトセットとして保存

詳しくは、Ableton公式のヘルプをご参照ください。
Liveセットの新しいテンプレートや空のテンプレートを設定する