コンテンツにスキップ

パターン集(レシピ)

すぐ使える実用パターン集です。コピペして元ノート / クリップ長を変えるだけで動きます。前提は 既定の stepsPerBeat = 4(16 分グリッド)

各レシピには使うヘルパー (🛠)、目的 (🎯) を 1 行で付記しています。詳しいヘルパーの仕様は 音楽ヘルパー / 数値ヘルパー / ホスト API を参照。

やりたいことレシピ
入力ノートを加工するオクターブダブリング5 度ハモリスケールスナップ2 倍速
ドラムパターンを作る4 つ打ち + スネア + HHユークリッド
アルペジオを作るchord で和音を分散元ノートを基音にしたアルペジエータ
コード進行を書くI-IV-V-I
メロディを生成するdrunk()urn()
LFO / オートメーションvelocity LFOCC1 三角波 LFOCC11 ADSR
確率的に変化させるHOF チェイン確率的ハーモナイズ再現可能な乱数
解像度を変える三連符シャッフル

オクターブダブリング・エコー

Section titled “オクターブダブリング・エコー”

🛠 onNote, setNote ・ 🎯 元ノートに 1 オクターブ上の遅れたコピーを追加(厚み + ステレオ感)

onNote((n) => {
setNote({ ...n }); // 元ノート保持
setNote({
pitch: n.pitch + 12, // オクターブ上
velocity: Math.round(n.velocity * 0.7), // 70% velocity
startBeat: n.startBeat + 0.5, // 半拍遅らせる
lengthBeats: n.lengthBeats,
});
});

🛠 onNote, setNote ・ 🎯 各ノートに 5 度(+7 半音)のハモリを重ねる

onNote((n) => {
setNote({ ...n });
setNote({ ...n, pitch: n.pitch + 7, velocity: Math.round(n.velocity * 0.8) });
});

スケールスナップ(フィルター)

Section titled “スケールスナップ(フィルター)”

入力ノートをスケール内の音に丸める。

🛠 scale, onNote, setNote ・ 🎯 外れた音を半音下げてスケール内に収める

const sc = scale("minor", 60);
const allowed = new Set(sc.map((p) => p % 12));
onNote((n) => {
if (allowed.has(n.pitch % 12)) {
setNote({ ...n });
} else {
setNote({ ...n, pitch: n.pitch - 1 }); // 半音下げてスケールへ
}
});

startBeatlengthBeats を半分にする。クリップ長を超えるノートは自動で切り詰められません — 必要なら自前でクリップ。

🛠 onNote, setNote ・ 🎯 入力フレーズを 2 倍速で詰めて再生

onNote((n) => {
setNote({
...n,
startBeat: n.startBeat / 2,
lengthBeats: n.lengthBeats / 2,
});
});

ジェネレータ(元ノート不要)

Section titled “ジェネレータ(元ノート不要)”

ユークリッド + マイナースケールでアルペジオ

Section titled “ユークリッド + マイナースケールでアルペジオ”

🛠 euclid, scale, degree, onBeat, setNote ・ 🎯 5/16 ユークリッドリズムにスケール音を当てたアルペジオ

const pat = euclid(5, 16);
const sc = scale("minor", 60);
onBeat((b) => {
const i = Math.floor(b * 4); // 16 分の通し番号
if (pat[i % pat.length]) {
setNote({
pitch: degree(sc, i % sc.length),
startBeat: b,
lengthBeats: 0.25,
});
}
});

4 つ打ちキック + 裏拍スネア + 8 分ハイハット

Section titled “4 つ打ちキック + 裏拍スネア + 8 分ハイハット”

🛠 onBeat, noteOn ・ 🎯 ハウス/4 つ打ちの基本ドラムパターン

onBeat((b) => {
if (Number.isInteger(b)) noteOn(36, 0.1, 100, b); // キック
if (Math.abs((b % 1) - 0.5) < 1e-6 && b >= 1) noteOn(38, 0.1, 90, b); // スネア(2,4 拍)
if (Math.abs((b * 2) % 1) < 1e-6) noteOn(42, 0.05, 70, b); // 8 分ハットHH
});

chord で和音を分散(アルペジオ)

Section titled “chord で和音を分散(アルペジオ)”

🛠 chord, onInit, setNote ・ 🎯 maj7 の和音を 16 分音符で 1 音ずつ分散

const ch = chord("maj7", 60);
onInit(() => {
ch.forEach((p, i) => {
setNote({ pitch: p, startBeat: i * 0.25, lengthBeats: 1 });
});
});

🛠 chord, transpose, onInit, setNote ・ 🎯 1 小節 = 1 コードで 4 小節分の進行を全音発音

const I = chord("maj", 60);
const IV = transpose(I, 5);
const V = transpose(I, 7);
const prog = [I, IV, V, I];
onInit(() => {
prog.forEach((ch, bar) => {
ch.forEach((p) => setNote({ pitch: p, startBeat: bar, lengthBeats: 1 }));
});
});

drunk() でランダムウォークメロディ

Section titled “drunk() でランダムウォークメロディ”

🛠 drunk, onBeat, setNote ・ 🎯 中心 60、最大歩幅 3 半音、48〜84 範囲のランダムウォーク

const d = drunk(60, 3, 48, 84);
onBeat((b) => {
if (Math.abs(b % 0.5) < 1e-6) {
setNote({ pitch: d(), startBeat: b, lengthBeats: 0.5 });
}
});

urn() で 7 音を一様にランダム配列

Section titled “urn() で 7 音を一様にランダム配列”

🛠 scale, urn, onBeat, setNote ・ 🎯 マイナースケール 7 音をランダムに(重複なし)配置

const sc = scale("minor", 60);
const u = urn(sc.length);
onBeat((b) => {
if (Math.abs((b * 2) % 1) < 1e-6) {
// 8 分ごと
setNote({ pitch: sc[u()], startBeat: b, lengthBeats: 0.5 });
}
});

既存ノートを保持しつつレイヤーを追加

Section titled “既存ノートを保持しつつレイヤーを追加”

🛠 onNote, onBeat, noteOn ・ 🎯 元ノートをそのまま残しつつ HH を上から重ねる

onNote((n) => setNote({ ...n })); // 元ノート保持
onBeat((b) => {
// ハイハットを上から重ねる
if (Math.abs((b * 2) % 1) < 1e-6) noteOn(42, 0.05, 70, b);
});

元ノートのリズムだけ使ってピッチを置き換え

Section titled “元ノートのリズムだけ使ってピッチを置き換え”

🛠 scale, degree, onNote, setNote ・ 🎯 タイミングは入力のまま、ピッチをドリアン上に再割当

const sc = scale("dorian", 60);
let i = 0;
onNote((n) => {
setNote({
...n,
pitch: degree(sc, i),
});
i += 1;
});

モジュレーション(LFO・エンベロープ・CC)

Section titled “モジュレーション(LFO・エンベロープ・CC)”

🛠 lfo, onNote, setNote ・ 🎯 サイン LFO で velocity を 70〜110 の間で揺らす

onNote((n) => {
const phase = n.startBeat / CLIP_LENGTH;
setNote({ ...n, velocity: 90 + 20 * lfo(phase, "sin") });
});

🛠 lfo, onBeat, setCc ・ 🎯 クリップ全体で 2 周期の三角波で CC1 を 14〜114 に揺らす

onBeat((b) => {
const phase = b / CLIP_LENGTH;
setCc({ ccNumber: 1, beat: b, value: 64 + 50 * lfo(phase * 2, "tri") });
});

🛠 envelope, onBeat, setCc ・ 🎯 ブレークポイント指定で CC11 にアタック→サステイン→リリース

const adsr = [
[0, 0],
[0.25, 110],
[0.5, 80],
[3.5, 80],
[4, 0],
];
onBeat((b) => {
setCc({ ccNumber: 11, beat: b, value: envelope(adsr, b) });
});

🛠 onNote, setCc ・ 🎯 各ノートの velocity を同じ beat の CC11 として書き出す

onNote((n) => {
setNote({ ...n });
setCc({ ccNumber: 11, beat: n.startBeat, value: n.velocity });
});

🛠 onCc, sampleCc, setCc ・ 🎯 入力 CC7 を一定グリッドでサンプル → 半分の値で書き戻し

// 入力 CC7 を半分の値で書き戻す。固定グリッドで掃引されるので、
// 元のブレークポイント数に関係なく滑らかに出力される。
onCc(({ beat }) => {
const base = sampleCc(7, beat);
setCc({ ccNumber: 7, value: Math.round(base * 0.5) });
});

🛠 setCcResolution, onCc, setCc ・ 🎯 高解像度(32 / beat)でクリップ全体に 1 周期のサイン LFO

// クリップ全体で 1 周期。解像度を上げるほど滑らか。
onInit(() => setCcResolution(32));
onCc(({ phase }) => {
setCc({ ccNumber: 1, value: 64 + 32 * Math.sin(phase * 2 * Math.PI) });
});

modCc で「読んで → 加工して → 書き戻す」を 1 行

Section titled “modCc で「読んで → 加工して → 書き戻す」を 1 行”

🛠 modCc, lfo, onCc ・ 🎯 入力 CC7 に LFO を加算(factory.js のラッパ関数)

// factory.js の modCc は sampleCc + clamp + setCc のラッパ。
onCc(modCc(7, (v, phase) => v + 10 * lfo(phase, "sin")));

🛠 every, sometimes, onBeat, setNote ・ 🎯 4 ステップに 1 度かつ 50% で発火(期待値 1/8)

// 4 ステップに 1 度かつ 50% 確率で発火(期待値 1/8)
onBeat(
every(
4,
sometimes(0.5, (b) => {
setNote({ pitch: 60, startBeat: b, lengthBeats: 0.25 });
}),
),
);

🛠 chance, weighted, onNote, setNote ・ 🎯 60% 確率でハモリ追加、ハモリ間隔は重み付き分布で選ぶ

const intervals = [0, 7, 12]; // ユニゾン / 5 度 / オクターブ
const w = [3, 5, 2]; // 5 度を多めに
onNote((n) => {
setNote({ ...n }); // 元ノート保持
if (chance(0.6)) {
// 60% の確率でハモリ追加
const semi = weighted(intervals, w);
setNote({
...n,
pitch: n.pitch + semi,
velocity: Math.round(n.velocity * 0.7),
});
}
});

🛠 seed, seededRandom, onNote, setNote ・ 🎯 文字列シードで毎回同じピッチオフセットを出す

seed("variation-A"); // 文字列で固定
onNote((n) => {
const offset = Math.floor(seededRandom() * 12) - 6; // -6..+5
setNote({ ...n, pitch: n.pitch + offset });
});

🛠 onBeat, setNote ・ 🎯 1 拍を 3 分割した 3 連符

onBeat((b) => {
if (Math.abs((b * 3) % 1) < 1e-6) {
setNote({ pitch: 67, startBeat: b, lengthBeats: 1 / 3 });
}
});

🛠 onBeat, setNote ・ 🎯 8 分グリッドの裏拍を 0.05 beat 後ろにずらすシャッフル感

onBeat((b) => {
// 8 分グリッドで、裏は少し遅らせる
if (Math.abs((b * 2) % 1) < 1e-6) {
const isOff = Math.abs((b % 1) - 0.5) < 1e-6;
setNote({
pitch: 60,
startBeat: b + (isOff ? 0.05 : 0),
lengthBeats: 0.25,
});
}
});

スタッター(同じピッチを連打)

Section titled “スタッター(同じピッチを連打)”

🛠 onNote, setNote ・ 🎯 1 ノートを 4 分割し、velocity を徐々に減衰させて連打

onNote((n) => {
const reps = 4;
for (let i = 0; i < reps; i++) {
setNote({
...n,
startBeat: n.startBeat + (i / reps) * n.lengthBeats,
lengthBeats: n.lengthBeats / reps,
velocity: Math.round(n.velocity * (1 - i * 0.15)), // 徐々に減衰
});
}
});

元ノートを基音にしたアルペジエータ

Section titled “元ノートを基音にしたアルペジエータ”

🛠 onNote, setNote ・ 🎯 入力ピッチをルートとして 1度→5度→8度→5度を分散

const pattern = [0, 7, 12, 7]; // 1度・5度・オクターブ・5度
onNote((n) => {
pattern.forEach((semi, i) => {
setNote({
...n,
pitch: n.pitch + semi,
startBeat: n.startBeat + i * (n.lengthBeats / pattern.length),
lengthBeats: n.lengthBeats / pattern.length,
});
});
});

確率分布を時間で変える(左から右へ密度が上がる)

Section titled “確率分布を時間で変える(左から右へ密度が上がる)”

🛠 chance, pick, scale, onBeat, setNote ・ 🎯 クリップの後半ほど発音密度が上がるビルドアップ

onBeat((b) => {
const density = b / CLIP_LENGTH; // 0..1
if (chance(density)) {
setNote({
pitch: pick(scale("pentaMinor", 60)),
startBeat: b,
lengthBeats: 0.25,
});
}
});

各元ノートを「そのピッチをルートとするコード」として鳴らす。

🛠 chord, onNote, setNote ・ 🎯 入力 1 音を min7 コードに展開(同タイミング・同長)

onNote((n) => {
chord("min7", n.pitch).forEach((p) => {
setNote({
pitch: p,
velocity: n.velocity,
startBeat: n.startBeat,
lengthBeats: n.lengthBeats,
});
});
});