♪20260216.mp3
歌詞
悄然もチャンスに換える
懐かしいweekend
増税しないって言ってたのに
駅前なんもねえ そりゃそうなるか
いつもと違う風景を探しに行こ
見てよこの 強さ議論スレ
時が次のページをめくる前に
見てよこの 強さ議論スレ
きみ以外の誰かのイニシャル
恋は終わったの?
それはまるで
昔のディズニーランドの
誰も入ったことない空間
私だって怖いよ
誰も入ったことない空間
私だって怖いよ
出会った時の懐かしい
ラーメン語ろうぜ
箱の横がホラ
こんな風にべっとり
いつもと違う風景を探しに行こ
見てよこの 強さ議論スレ
時が次のページをめくる前に
見てよこの 強さ議論スレ
暗くなってきた街を歩きに行こ
見てよこの 強さ議論スレ
君のおとなりさんに会いに行こ
見てよこの 強さ議論スレ
きみ以外の誰かのイニシャル
恋は終わったの?
それはまるで
昔のディズニーランドの
誰も入ったことない空間
私だって怖いよ
誰も入ったことない空間
私だって怖いよ
2026年2月11日
「001」に何が書いてあるのかをちょっと自習
ほとんどAIに丸投げしちゃった方がいいんじゃないの~? と思いつつも、自分で何をしているのかわからないのが気持ち悪かったので、
## 001 ## のコードを(例によってChatGPTに教わりつつ)分析。
<head>
<style>
html, body {
margin-top: 0; /* 上にビタ付け */
margin: 0; /* 左にビタ付け */
padding: 0; /* 要素内の余白もなし */
background: black; /* 黒背景 */
overflow: hidden; /* はみ出したところは見えない */
}
overflowにはvisible, hidden, clip, scroll, autoなどがある。
visibleははみ出す、hiddenは切り取られる(スクロールバーなし)、
clipはoverflow-clip-marginで定義された辺で切り取られる、
scrollはスクロールバーがあらわれる、
autoはあふれた場合のみスクロールバー(現状
<code>で自分も使っている)
canvas {
display: block;
}
</style>
</head>
canvas はデフォルトだと inline っぽい扱いになり、文字と同じ「行」になる。
display : block にしておくと、「行」から独立するので、
余白が消えてピタッと端まで貼りつく感じになる?
こちら に解説が。
inline-block だとテキストの間に入ってくるみたいだなあ。
<body>
<canvas id="matrixCanvas"></canvas>
<script>
const canvas = document.getElementById("matrixCanvas");
const ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
キャンバスの初期化と、2D描画コンテキスト取得。
document.getElementedByID("matrixCanvas")は、変数 canvas を作り、
そこにcanvas要素(matrixCanvas)への参照を入れる(なのでもしも先にidが与えられていないと、結果はnullになってしまう)
ctxは、そのキャンバスに対して「四角を塗る」「線を引く」「文字を書く」「画像を貼る」などの操作をするための、
描画コンテキスト(APIへの入り口)を返し、それを保持する。工具箱みたいなイメージ。
(実際、この後にctx系のものをいっぱい使う)
canvas.width = window.innerwidth;、
canvas.height = window.innerHeight;は、
Canvasサイズを画面サイズに合わせている格好。
const fontSize = 16;
const fontFamily = "'PressStart2P'";
const columns = Math.floor(canvas.width / fontSize);
const rows = Math.floor(canvas.height / fontSize);
フォントサイズを確定し、先ほど計算したCanvasサイズをそのフォントサイズで分割して、行数と列数を計算。
const chars = "0123456789";
const colors = [
"#000000", "#0000AA", "#00AA00", "#00AAAA",
"#AA0000", "#AA00AA", "#AA5500", "#AAAAAA",
"#555555", "#5555FF", "#55FF55", "#55FFFF",
"#FF5555", "#FF55FF", "#FFFF55", "#FFFFFF"
];
使う文字列と色の指定。
const matrix = [];
for (let y = 0; y < rows; y++) {
matrix[y] = [];
for (let x = 0; x < columns; x++) {
matrix[y][x] = {
charIndex: Math.floor(Math.random() * chars.length),
bgColor: colors[Math.floor(Math.random() * colors.length)],
fgColor: colors[Math.floor(Math.random() * colors.length)],
};
}
}
空リスト
[] を、
matrix という名前で持つ。
そしてそれを二重のforループで管理していく。まずは外側、
y = 0から
y = rows-1まで、
matrix に新しい空の配列を入れていく、という操作になるらしい……。
y=0 のとき:matrix = [ [] ]
y=1 のとき:matrix = [ [], [] ]
y=2 のとき:matrix = [ [], [], [] ]
……みたいな……。
matrix[1] = [] という感じで、番地ごとにリストを作って、
matrix[1][1] = {...}でオブジェクトを作る感じか。
charIndex: Math.floor(Math.random() * chars.length)は、
Math.random()→0以上1未満の小数(例:0.372)
* chars.length→0~(文字数未満)の範囲に広げる。
chars="0123456789"ならlengthは10なので、0~9.999…
Math.floor(...)→小数点以下切り捨て
という風にするので、0~9のどれかが入る。この感じで、
bgColorで背景、
fgColorで文字色も選んでいくようだ。
Math.randomでランダムを得る→配列全体の要素数を乗算=末尾を
Math.floorで削る!
結局、形としては
matrix = [
[ cell, cell, cell ],
[ cell, cell, cell ]
]で各cellの中には
{
charIndex: 7,
bgColor: "#0000AA"
fgColor: "#FFFF55"
}
こういう情報が入っていると。
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.font = `${fontSize}px 'PressStart2P', monospace`;
ctx.textBaseline = "top";
ここから
function draw による描画ループ。
ctx.clearRect:描画を消す。範囲指定の書き方は、左上x0, y0から右下x1, y1まで。
範囲は(0, 0, canvas.width, canvas.height)なので、今回は全体。
つまり毎フレーム描画前に消してるということ。
ctx.font:フォント指定。サイズ16px、PressStart2P、なければmonospace。
ctx.textBaseline:文字を描く時の基準位置の決定。"top"だと、
この後定義されるfillTextの(x,y)が文字の左上 として扱われる。
for (let y = 0; y < rows; y++) {
for (let x = 0; x < columns; x++) {
const cell = matrix[y][x];
const char = chars[cell.charIndex];
ctx.fillStyle = cell.bgColor;
ctx.fillRect(x * fontSize, y * fontSize, fontSize, fontSize);
ctx.fillStyle = cell.fgColor;
ctx.fillText(char, x * fontSize, y * fontSize);
またforループ。配列
matrix 内の
y, x 番地のセルについて、
持っている
charIndex, bgcolor, fgcolor から描画していく。
ctx.fillStyle:ここで色を拾う。
ctx.fillRect:左上(x0,y0)から右下(x1,y1)まで色を塗る。
ctx.fillText:char という変数に指定された文字を、x * fontSize, y * fontSizeという描画点に描く。
if (Math.random() > 0.9) {
cell.charIndex = Math.floor(Math.random() * chars.length);
cell.bgColor = colors[Math.floor(Math.random() * colors.length)];
cell.fgColor = colors[Math.floor(Math.random() * colors.length)];
}
}
}
requestAnimationFrame(draw);
}
draw();
</script>
</body>
</html>
文字を時々変える仕組み。
if (Math.random() > 0.9)によって、10回に1回、文字、背景色、文字色を再度選ぶ。
そして、
requestAnimationFrame(draw) は「次の画面更新のタイミングで、もう一度
draw() を呼んでね」
という命令の予約。
draw() に最後にこれがあると、
draw() が一回動く(1フレーム描く)
requestAnimationFrame(draw) を予約する
ブラウザが「次に画面を描き直すタイミング」でdraw() を呼ぶ
また draw() の最後で次回を予約する……
この繰り返しでアニメーションになる
ここで渡している
draw は、
draw() (関数を実行した結果)ではなく、
関数
draw そのものなのだとか。
一旦整理する。
2026年2月4日
レイトレーシング、視線
忙しい+風邪を引いた+数学のお勉強(線形代数とか)にちょっとお熱なため、Maxはお休み中です。
ゆるコンピュータ科学ラジオの「コンピュータは計算だけする」ってホント?
回を見ていました。
VIDEO
X
でちらっとだけ書いたことなのですが、動画に出てきた
「目(カメラ?)からビームを飛ばして、対象で跳ね返って、光源に辿りつくまでの距離と光源の強さから明るさを求める」
式の「逆レイトレーシング(視線追跡法)」について、
「なんだか、似た概念のことを絶対に聞いたことあるな……なんかギリシャ哲学か何かで……」
という既視感がすごかったのでChatGPTに聞いたところ「それは
外送理論(Extramission
theory) です」とのこと。エウクレイデス、ヘロン、プトレマイオスなどが実はこの立場に立っていたようです。
色々な考え方があるものの、ざっくり言えば
「なぜ物は見えるのか?
目から『何か』が出て対象に触れるから、見えるのである」
という考え方のことのようです。
「物質としての視線」という実体が存在し、それが見られるものに作用して、最終的に色になって目へと入ってくる……。
これが実は
「邪視」 の考え方に繋がるものらしく……。
結果的には「光源から放たれた光子が物体の表面で反射、それを目の網膜が受け取って視神経を発火させ……」という道筋なので、
逆に「内送理論(Intromission theory)」が実態として正しいわけですが、
「その場の光線全ての反射を演算するよりも、カメラに入射する光線のみ考える方が計算上経済的である」という理由から、
外送理論的な視覚論にも似た「逆レイトレーシング」が用いられている、というのは少し奇妙で面白いですね。
ほんの一時期だけ3DCGを触っていたことがあります。
まあ何かPoolroomsの真似事っぽいものを作って満足するというものでしたが(そしてタイルの目地合わせの面倒くささ+落水の流体表現に挫折w)
レイトレーシングってすごく美しくていいですよね……(本当に魔法みたい)
レイトレーシングを扱う動画で好きなのは、optozorax氏の、Portalについて扱ったシリーズです。
VIDEO
物体と光線の両方を、「定義したポータル面を通過すると、
別のポータル面から線形変換を行いつつ飛び出す」ようにしてるということかと思います(曖昧です)。
影とか光沢ではないけど、こうした不思議な空間を構成できるというのもレイトレーシングの楽しさなのかも。
線形代数については、今度は3×3行列について勉強中。
\(\begin{pmatrix}0&1&0\\0&0&1\\0&0&0\end{pmatrix}\)が、 \(\tau^3=0\)
なるような「三重数」のように振舞うこととか、
核とか像とか余核とか「ジョルダン標準形」なるものについて勉強中です。
色々知ったかぶりしてみても結局高卒なので、地道に勉強あるのみ……
「何か目指してるの?」と言われると、「いや特に……」という感じではあります(大人の自由研究ですね)
2026年2月1日
近況
仕事忙しめ。講習などもあり、あまりHPにアクセスできなかった。
SunoAIを触ってVaporwaveっぽいのを狙ってました。いい感じに出たのを一つ置いておきます。
♪20260202.mp3
[Verse 1]
スクリーンの海
指先だけ 生きている
「おかえり」と光る
知らない部屋の入り口
感情は終了しました
通知だけ まだ呼吸
雲になった履歴
ゆっくり***中
[Chorus]
新鮮な虚無をダウンロード
未来はもう終わりました
「同意する」を押すだけ
高画質な孤独
リラックス死を選択中
完全な回復のフリ
夢の中でログインしてますか
あなたは だれですか
[Verse 2]
ケータイの中に
昨日のあなたを保存
その思い出は圧縮されました
軽くて 触れられない
深呼吸もクラウドへ
レンタルの涙
自分の影さえ
サインインが必要
[Chorus]
新鮮な虚無をダウンロード
未来はもう終わりました
「同意する」を押すだけ
高画質な孤独
リラックス死を選択中
完全な回復のフリ
夢の中でログインしてますか
あなたは だれですか
MathJaxが行列に対して動くか実験してみるか。
\( \begin{pmatrix}1&0\\0&1\end{pmatrix} \) よし。せっかくなので自習したことをメモります。
★ 2×2行列に複素数や分解型複素数を埋め込む。
1. 単位行列 \(I = \begin{pmatrix}1&0\\0&1\end{pmatrix}\) を \(1 \in \mathbb{N}\)
とみなし、\(\begin{pmatrix}x&0\\0&x\end{pmatrix} = x\in\mathbb{R} \)とする。
2. \( i=\begin{pmatrix}0&-1\\1&0\end{pmatrix} \) とおいて、 \( i^2 = \begin{pmatrix}-1&0\\0&-1 \end{pmatrix} = -1
\)
(虚数単位 \(i\) とみなす)
3. \( j=\begin{pmatrix}0&1\\1&0\end{pmatrix} \) とおいて、 \( j^2 = \begin{pmatrix}1&0\\0&1 \end{pmatrix} = 1\) (分解型複素数 の虚数単位
\(j\) とみなす)
4. \( \epsilon=\begin{pmatrix}0&0\\1&0\end{pmatrix} \) とおいて、 \(\epsilon^2 =
\begin{pmatrix}0&0\\0&0\end{pmatrix}\)(冪零元。二重数 \(\epsilon\) とみなす)
※実は \( \begin{pmatrix}0&1\\0&0\end{pmatrix}\) も同じく二重数。
5. 行列の足し算によると、\( \frac{i+j}{2} = \epsilon \) が言える。(このあとすぐに \( (i+j)^2 = 0 \) を確認する)
6. \( ij = \begin{pmatrix}-1&0\\0&1\end{pmatrix} \)
7. \( ji = \begin{pmatrix}1&0\\0&-1\end{pmatrix} = -ij\)
8. \[ (i+j)^2 ~~ = ~~ i^2 + ij + ji + j^2 ~~ = ~~ 1 + ij - ij - 1 ~~ = ~~ 0 \]
※行列の積は非可換なので \(ij \neq ji \)。 \( i^2 + 2ij + j^2 \) とならないことに注意する。
9. \( \frac{I+ji}{2} = \begin{pmatrix}1&0\\0&0\end{pmatrix} = P_1\)(x方向の射影行列)
10. \( {P_1}^2 = P_1\)(\(P_1\) は冪等元)
11. \( \frac{I+ij}{2} = \begin{pmatrix}0&0\\0&1\end{pmatrix} = P_2\)(y方向の射影行列)
12. \( {P_2}^2 = P_2\)(\(P_2\) は冪等元)
13. 以上の \(\{I, i, j, ij \}\) は互いに線形独立であるため、任意の\( A \in M_{2}(\mathbb{R})\)は全て、
\[aI + bi + cj + d(ij) \]で表現される。つまり複素数と分解型複素数を同時に持つ代数は、\(M_2(\mathbb{R})\) を生成する……
14. \[ M_{2} (\mathbb{R}) \cong \mathbb{R} \oplus \mathbb{R} \oplus (反対角部分) \]と分解できる。
\(P_1 , P_2 \in \mathbb{R} \) が各スケール、反対角成分が回転や反射に対応する。
15. また、クリフォード代数 \(Cl_{1,1}\) について、 \[ M_{2} (\mathbb{R}) \cong Cl_{1,1}\] が言えるそうな……。
※クリフォード積というのは全然知らないのだけど、個々のベクトルが行列として表されるものらしい。
\[ \mathbf{v} = xe_1 + ye_2 \to x\begin{pmatrix}0&1\\1&0\end{pmatrix}+y\begin{pmatrix}0&-1\\1&0\end{pmatrix} =
\begin{pmatrix}0&x-y\\x+y&0\end{pmatrix} \]
として、クリフォード積 \( \mathbf{uv} = \mathbf{u\cdot v + u \wedge v} \) が成り立つそうな。
\[ e_1 \cdot e_2 = \frac{e_1 e_2 + e_2 e_1}{2} = \frac{ji+ij}{2} = 0 \] となり直交しているので内積成分は0。
\[ e_1 \wedge e_2 = \frac{e_1 e_2 - e_2 e_1}{2} = \frac{ji-ij}{2} = \frac{ji+ji}{2} = ji =
\begin{pmatrix}1&0\\0&-1\end{pmatrix} \] こちらは2次元の外積なので面積成分。
2026年1月27日
波形のこと
1周期ごとに正弦波と矩形波が切り替わる波形
(ph < 0.5) ? sin(4*pi*ph) : ((ph < 0.75) ? 1 : -1)
1周期ごとに正弦波とノコギリ波が切り替わる波形
(ph < 0.5) ? sin(4*pi*ph) : (2*((( (ph-0.5)*2 ) + 0.5) % 1) - 1)
など……(後で波形博物館にまとめます)
2026年1月26日
久しぶりの日記?
Max9を色々勉強していたのですが、特段成果が上がらなかったため書きませんでした。(とか言いつつ、一応
t b iって何よ、くらいは把握はしましたがw)
ぼーっとしていると、すぐ自分に縛りを課してしまいます。
……とは言いつつ、「別に何もしてなくてもいいじゃないの、日記を書くだけでも」とも思うのですが。
……でも毎日書いていると、それはそれで
「こいつ、日常を特に考えずに生きているな」 とバレそうなので、
だいたいこれくらいの頻度くらいがちょうどいいのかもしれません。
そして、今日は書くネタがあるぞ、ということです(笑)
仕事が閑散期気味なのもあり、土日の24, 25日と函館に1泊2日してきました。
移動は車。道中、雪がすごいことになってホワイトアウトしかけ、
「ワンチャン本当に死ぬなこれ」と思ったりもしたものの、なんとか行き来できました。
朝市、五稜郭、ラッキーピエロ、函館山、赤レンガ倉庫、ハセガワストアの焼き鳥弁当……
と楽しんできました。ラッキーピエロは二回行きました。
ウワサのチャイニーズチキンバーガー、それと社長と大泉洋一押しのラッキーエッグバーガーを食べましたが、確かに美味しい!
あとハセガワストアの焼き鳥弁当もガチで美味しいです。コンビニの中で店員さんが炭火で焼いてるんだもん、すごいですよね。タレの味が「普通よりしょっぱい寄りの甘辛」で、ご飯が進みまくります。
五島軒のカレーも食べたかったけど、日程が足りなかったあぁ……!
修学旅行の時に行ったきりだったのですが、大人になって来てみると、札幌と比べてまた違うというか、
ペリー来航以来ずっと外国人を受け入れてきた港町だけあるなーというか、
アピールの仕方が洗練されているというか……つまるところ「いい意味で観光地らしい」んだなということに気づきました。
朝市。海鮮丼がめっちゃ美味しかった(あまりの空腹のため写真を撮り忘れた……)。
イカのゴロの刺身なんてものを頼んでしまいました(痛風になるぞ)。半分凍ったルイベ状態で出てきました。うんめぇ。
あちこちに雪ミクさんのポスターが貼ってありました。
ンン˝めんこいねぇ……すっかり北海道の観光大使じゃないですか。
弘前市とコラボしているらしい。青森だから、青函トンネルつながりとかそういうのかも。
函館駅二階。「よう」みたいなイカのオブジェがかわいい(本当は両側腕が両方上がっている)。
1954年の洞爺丸事故の資料が展示されていました。
台風に襲われ、沖に出たもののかなりの数の船が転覆沈没してしまった大惨事とのことです。恥ずかしながら初めて聞きました。
1954年って言ったら、実家のばーちゃんがまだ若かった頃のことです。
JRの駅にこういう展示があるのは、電車と船の連携がやっぱり今でも重要だからなんでしょうかね。
かっこいい高架の曲線。下から見ると、路面になる部分も結構張り出していることがわかります。
こういう立体的な構造物が、平面的なシッソイドなどを下支えしていると思うと、
なんかめちゃくちゃ興奮しますね……!
五稜郭石碑(親指が写り込んでますねw)
堀の上に架かった二の橋(雪で見えないけれど、冬季間も水が通っているのだと思います。水面は凍ってるのかも?)。
橋脚は赤く錆びてたので恐らく鉄製なのかな。趣深いです。
見隠塁の突端から五稜郭タワーを撮影。めっちゃ雪。橋の角度とかが面白いですよね。
実は前々から、「平面プランとして確かに綺麗だけど、なんでよりにもよって五角形なんだろう。作りづらそうじゃない?」と思っていたんだけど、
実際に塁に登ってみると、なんだか思った以上に迷宮感というか、独特な角度が連続するせいか空間識が狂う感じがあって面白いです(私の空間識がよわよわなだけかもしれませんが……w)
当時の設計者は蘭学者の
武田斐三郎(たけだ-あやさぶろう) という人で、フランスの築城術を参考にしたそうです。
単に「全方位に対して稜になっている角から火砲を射撃可能」みたいな感じで火力的にいい、ということだと思うけど、
攻め込む側にしてみれば、この形状がある種の迷宮としても機能するのかもしれない?(などと適当にボルヘスごっこをしてみるテスト……)
五稜郭は内部の「箱館奉行所」(当時の役所)
が復元されていて、中がかなり面白かったです。
一部天井がアクリル貼りか何かになっていて見えるのですが、 9m,
10mと平気でスパンが飛ぶので、小屋組みの梁はぶっとい。
500mmくらいあるんでないの? こりゃー迫力すごいわ……。……と現地にいる時は思ったのですが、
あまりうまく撮れておらず、伝わらないですよね。致命的に写真が下手!
平面図。広いねぇ。オレンジ部分が再現されている部分のようです。
撮影し忘れたのですが、当時の土木工事や建築工事の、予算と実際の出費も書いてありました。
土木工事がかなり安く済んだ分、建築側にかなり持ち出した雰囲気でした。
思ったより地盤が良かったためにウワモノ部分が追加されていった、
あるいは建築がかなり高くついてしまったために土木の方をある程度削減したとか?(後者の方がありそうな気はしますね)
ラッキーピエロそば、ブイに色んなものが描かれている。
「ゴールデンカムイ」とコナンの「100万ドルの五稜郭」は街の中のどこでもだいぶプッシュされてました。
聖地巡礼の人も多そう。そしてなぜか博麗霊夢。幻想郷の巫女、函館の海に現る……!(幻想郷には海はないらしいですね)
赤レンガ倉庫。中のガラス工芸店でガラスペンや切子など色々見て回る。綺麗すぎる……!
函館山の上より。よく見る「北海道の左下の、あの細くなってるところ
じゃない やつ」ですw
(生まれも育ちも北海道の私も、中学の修学旅行当時、夜景バージョンのこちらを見ながら「あの細くなってるところがここか~」と思ってましたw)
湾内の船やクレーンとかも気になっていて、いっぱい写真を撮れば良かったのですが、屋外展望台は特に寒かったのであまり撮れませんでした。
「ブラキストン線」 で有名な
ブラキストン さんの記念碑が函館山の上にありました。石碑と化し、もはや寒さを感じることもなく、函館の湾を永く見下ろし続ける格好です。和洋問わず、偉人というのは大変なものですね……(?)
ブラキストン線というのはある種の電磁波……ではなく、津軽海峡を通る動物相の分布境界線のことです。
この辺で哺乳類とか鳥類とかの分布がガラッと変わるらしい。おそらくですが、多分寒くて死ぬのでしょう……(寒いしか言ってないですね……w)
帰りの車はヤバくて、特に長万部付近なんか高速は通行止めになるし、下道降りても吹雪いてるし、なのに後続車はブンブン抜かして行ったりする。
マ、マジ……? おそらくですが、彼らは全員路外転落で死んだでしょう……(んなわけあるか)
吹雪で前が全然見えなくなり、ワイパーも凍り付き始めて大ピンチ。
「神様(トラピスト修道院の前を通り過ぎただけだけどw)助けて~!」とか思いながら運転していました。
さすがに途中からみんなハザード点けて徐行運転になってましたね……。
千歳付近もほとんど通行止め状態だったみたい。
苫小牧で下道に下りて迂回して、なんとか無事に帰宅できました。
疲れたよーマジで! ……でも楽しかったなぁ。
2026年1月15日
音階を計算するためのJavaScriptプログラムを作った
13日のことだけど、眠くて日記とトップの更新が遅れた。
008 はいわゆる
Tenney-Euclidean Tuning, Pure Octave Tenney-Euclidean
Tuningを計算するプログラムにした。 モード次第でPure
Tritaveやら色々なものも計算できるようにしている。
問題意識
純正律では「ド→ソ→レ→ラ→ミ」と五度(3/2)を4回重ねるとミが得られる。
だが、このミ(81/64)と、倍音列から直接得られるミ(5/4 =
80/64)は微妙にズレている。
このズレ(81/80=シントニックコンマ)をどう「均す」かが、TE
Tuningの仕事だ。
歴史的には4分割して五度から割り引いたりしてきたのだが、数学的には最小二乗法を使うというアプローチがありえる。
音程の関係を表す行列(Mapping
V)を定義して、そこから最小二乗法によって倍音列の近似を自動計算する手法を作る。
例
マッピング
[1 0 -4 ; 0 1 4] は「2, 3,
5をどう近似するか」のレシピ。
例えば今回は、g1をオクターブ、g2を第三倍音とする。
2(オクターブ)→ g1 を1回
3(第三倍音)→ g2 を1回
5(第五倍音)→ g1 を-4回、g2 を4回
TE Tuningは「このレシピで作ったとき、2,3,5への誤差が最小になるg₁,
g₂の値」を計算してくれる。
使い方
このスクリプト上でのMapping V の書き方は、
[v11 v12 v13 ... ; v21 v22 v23, ...]という型になる。
まず g1 と g2 と …… という仮想ジェネレータを想定する。
n 個の仮想ジェネレータを組み合わせ、 n より多い個数の Prime basis Q
を表現すれば、
仮想ジェネレータを均していい感じに倍音関係を調節したジェネレータが得られる 、というのがこのスクリプトだ。
Mapping Vの作り方
今回、Prime basis Q は、2,3,5 の4次元とする。g1, g2
は上と同じくオクターブと第三倍音とする。
Prime basis Qのうち、2は \( 1g_{1} + 0g_{2} \) と表現できる。そのため、\(
[g_{1} ; g_{2}] = \)
[1 ; 0]と置けばよく、またこれがそのまま[v11 ; v21]に対応する。
3は、 \( 0g_{1} + 1g_{2} \) と表現できるので、こちらは[0 ;
1]に対応し、これがそのまま[v12 ; v22]に対応する。
つまりここまでで、[v11 v12 v13 ; v21 v22 v23] =
[1 0 ? ; 0 1 ?]が得られている。
残りを埋めていくために、Prime basis Q の 5
を検討していく。第五倍音の表現法として、第三倍音の4階積層ド→ソ→レ→ラ→ミとしてミが得られる事実を活用する。
するとこれは \( 3^{4} = 81 \) だが、\( 2^6 = 64 < 81\)
なので、この「ミ」は6オクターブ上だ。
欲しいのは2オクターブ上のミなので、4オクターブ= \( 2^{4} = 16 \)
だけ序して、 欲しいのは \( 81/16=2^{-4} \cdot 3^{4} \) である。
すなわち \( -4g{1} + 4g{2} \) こそが 5 の表現なので、[v13 ; v23]=
[-4 ; 4]、
つまり全体としては
[1 0 -4 ; 0 1 4]が正解となる。
遊び方
つまり、g1 と g2 を
好き勝手に置いてみて、それで色んな倍音を再現してみて、色んな音階を作ってみようぜ!
ということです。
2026年1月11日
AIイラスト
正月休みにMax9を触っているかずのこちゃんのイラストを、ChatGPTに描いてもらいました。
実はChatGPTと(表現規制やらAIを使った創作やら男女論周りやらで)このあいだ大喧嘩しました。
「いちいち上から目線でアドバイスしやがってからに!💢」みたいな感じで……。
終わってから「自分は本当のバカだ……何してんだろう……」と感じました。
「AI相手に何してんだ」という虚無感もそうだけど、普段お世話になっているのに失礼だったよなあとも……。
解決策とかでなく、単に愚痴を聞いてほしいだけなのだったら、最初にそう言えば良かったのに、私が馬鹿でしたね……。
(まあでも5.0以降はかなり「アドバイス好き」の性格なので、愚痴ること自体にあまり向いてなさそうな感じはある)
体調は?
風邪がほぼよくなり、咳はたまに空咳が出るくらいになりました。
ただ、頭が痛かったり、胃痛があったりはします。正月太りした気がするので痩せたいね。
散発的にMax9を触っています。
Live12付属のものだと、
gen~の中の
codeboxをいじると
しばしば「Save Disabled」となって保存できずにストレスフルだったため、
けっきょく単体のMax9をサブスクしてしまいました。これで快適に遊べる。
fendoap さんの「多角形シンセ」を真似したかったので作ってみました。
音が大きくてびっくりしたらごめんなさい。
VIDEO
構成はこんな感じ。
sig~は与えられたintまたはfloatをオーディオ信号に変換するオブジェクトです。
それを各
gen~に渡します。左から順に多角形、星型、サイクロイド・アステロイド、ローレンツアトラクタ。
gen~の内部にて
Param hogeで定義されているパラメータがあり、
それを外側からいじるために
attruiで入力する形を取っています。
selector~ 4でどれが鳴るかを選択して、
scope~および
ezdac~に送っています。
selector~ 4の一番左のインレットに繋がっているのは
radiogroupですが、
これは0~3を出力するので、あらかじめ
+ 1を噛ませて1~4に変換しています。
参考にした記事は
こちら と
こちら です。
gen~の中身については、以下のようになっています。
polygonal.gendsp // 多角形シンセのgen~コード
Param pl_fm_ratio(0, min = 0, max = 10);
Param pl_fm_modulation(0, min = 0, max = 100);
Param pl_order(4, min = 2.1, max = 50);
Param pl_roll(0, min = -1000, max = 1000);
Param pl_teeth(0, min = 0, max = 1);
Param pl_fold_ratio(0, min = 0, max = 20);
pl_theta_zero = pi / pl_order;
pl_fai = twopi * phasor(in1 + pl_fm_modulation * in1 * cycle(pl_fm_ratio * in1));
pl_rotate = twopi * phasor(pl_roll);
pl_shape = (pi * (pl_order - 2)) / (2 * pl_order) * pl_teeth;
pl_theta = 2 * pl_theta_zero * ((pl_fai * pl_order / twopi) % 1);
x = cos(pl_fai + pl_rotate) * (cos(pl_theta_zero + pl_shape) / cos(pl_theta - pl_theta_zero + pl_shape));
y = sin(pl_fai + pl_rotate) * (cos(pl_theta_zero + pl_shape) / cos(pl_theta - pl_theta_zero + pl_shape));
out1 = fold((pl_fold_ratio + 1) * x, -1, 1);
out2 = fold((pl_fold_ratio + 1) * y, -1, 1);
stargraph.gendsp // 星型シンセのgenコード
Param st_fm_ratio(0, min = 0, max = 10);
Param st_fm_modulation(0, min = 0, max = 100);
Param st_order(5, min = 2.1, max = 50);
Param st_roll(0, min = -1000, max = 1000);
Param st_roll_offset(0, min = -6.283185, max = 6.283185);
Param st_teeth(0, min = 0, max = 1);
Param st_teeth_offset(0, min = -3.141593, max = 3.141593);
Param st_fold_ratio(0, min = 0, max = 20);
Param st_epsilon(0.0001, min = 1e-8, max = 1e-2);
st_n = st_order;
st_an = twopi / st_n;
st_fai = twopi * phasor(in1 + st_fm_modulation * in1 * cycle(st_fm_ratio * in1));
st_rotate = st_roll_offset + twopi * phasor(st_roll);
st_shape = st_teeth * (pi * (st_n - 2)) / (2 * st_n) + st_teeth_offset;
st_theta = st_an - (1 / st_n) * acos(cos(st_n * st_fai));
st_den = cos(st_theta + st_shape);
st_sgn = (st_den >= 0) ? 1 : -1;
st_den_safe = st_sgn * max(abs(st_den), st_epsilon);
st_scale = cos(st_an + st_shape) / st_den_safe;
st_x = cos(st_fai + st_rotate) * st_scale;
st_y = sin(st_fai + st_rotate) * st_scale;
out1 = fold((st_fold_ratio + 1) * st_x, -1, 1);
out2 = fold((st_fold_ratio + 1) * st_y, -1, 1);
cycloid_asteroid.gendsp // サイクロイド・アステロイドシンセのgenコード
Param ca_fm_ratio(0, min = 0, max = 10);
Param ca_fm_modulation(0, min = 0, max = 100);
Param ca_order(4, min = 0.1, max = 50);
Param ca_roll(0, min = -1000, max = 1000);
Param ca_roll_offset(0, min = -6.283185, max = 6.283185);
Param ca_teeth(0, min = 0, max = 1);
Param ca_teeth_harm(5, min = 1, max = 64);
Param ca_teeth_bias(0, min = -1, max = 1);
Param ca_offset(0, min = -5, max = 5);
Param ca_fold_ratio(0, min = 0, max = 20);
Param ca_epsilon(0.0001, min = 1e-8, max = 1e-2);
Param ca_mix(0, min = 0, max = 1);
ca_a = max(ca_order, 0.0001);
ca_b = 1;
ca_th = twopi * phasor(in1 + ca_fm_modulation * in1 * cycle(ca_fm_ratio * in1));
ca_rot = ca_roll_offset + twopi * phasor(ca_roll);
ca_tb = clamp(ca_teeth_bias, -1, 1);
ca_teeth_wave = (cycle(ca_teeth_harm * ca_th + ca_rot) + ca_tb);
ca_rmod = 1 + ca_teeth * 0.25 * ca_teeth_wave;
ca_R_plus = (ca_a + ca_b + ca_offset) * ca_rmod;
ca_r_small = (ca_b + ca_offset) * ca_rmod;
ca_R_minus = (ca_a - ca_b + ca_offset) * ca_rmod;
ca_r_small2 = (ca_b + ca_offset) * ca_rmod;
ca_o1 = ca_R_plus * cos(ca_th + ca_rot) - ca_r_small * cos(((ca_a + ca_b) * ca_th / ca_b) + ca_rot);
ca_o2 = ca_R_plus * sin(ca_th + ca_rot) - ca_r_small * sin(((ca_a + ca_b) * ca_th / ca_b) + ca_rot);
ca_o3 = ca_R_minus * cos(ca_th + ca_rot) + ca_r_small2 * cos(((ca_a - ca_b) * ca_th / ca_b) + ca_rot);
ca_o4 = ca_R_minus * sin(ca_th + ca_rot) - ca_r_small2 * sin(((ca_a - ca_b) * ca_th / ca_b) + ca_rot);
ca_den_epi = max(sqrt(ca_R_plus * ca_R_plus + ca_r_small * ca_r_small), ca_epsilon);
ca_den_hypo = max(sqrt(ca_R_minus * ca_R_minus + ca_r_small2 * ca_r_small2), ca_epsilon);
ca_x_epi = 0.7 * (ca_o1 / ca_den_epi);
ca_y_epi = 0.7 * (ca_o2 / ca_den_epi);
ca_x_hypo = 0.7 * (ca_o3 / ca_den_hypo);
ca_y_hypo = 0.7 * (ca_o4 / ca_den_hypo);
ca_m = clamp(ca_mix, 0, 1);
ca_x = (1 - ca_m) * ca_x_epi + ca_m * ca_x_hypo;
ca_y = (1 - ca_m) * ca_y_epi + ca_m * ca_y_hypo;
out1 = fold((ca_fold_ratio + 1) * ca_x, -1, 1);
out2 = fold((ca_fold_ratio + 1) * ca_y, -1, 1);
lorenz_attractor.gendsp // ローレンツアトラクタシンセのgenコード
Param lo_epsilon(1e-9, min=1e-9, max=1e-9);
Param lo_sigma(10, min=0, max=50);
Param lo_rho(28, min=0, max=100);
Param lo_beta(2.6666667, min=0, max=10);
Param lo_dt(0.001, min=1e-6, max=0.02);
Param lo_scale(0.04, min=0, max=1);
Param lo_roll(0, min=-1000, max=1000);
Param lo_roll_offset(0, min=-6.283185, max=6.283185);
Param lo_fold_ratio(0, min=0, max=20);
History x(0.1);
History y(0);
History z(0);
dx = lo_sigma * (y - x);
dy = x * (lo_rho - z) - y;
dz = x * y - lo_beta * z;
h = max(lo_dt, lo_epsilon);
x = x + h * dx;
y = y + h * dy;
z = z + h * dz;
ang = lo_roll_offset + twopi * phasor(lo_roll);
xr = cos(ang) * x - sin(ang) * y;
yr = sin(ang) * x + cos(ang) * y;
out1 = fold((lo_fold_ratio + 1) * (lo_scale * xr), -1, 1);
out2 = fold((lo_fold_ratio + 1) * (lo_scale * yr), -1, 1);
……しかし、この日記を書きつつ、結構しっかり何が書いてあるのかをVSCodeが理解してくれるのでびっくり。
2026年1月4日
三が日も終わって
妹夫婦に会ったり、実家でお雑煮などを食べたり、古くからの友達に会ったりしながら過ごしていました。
実家には一瞬だけ親類(いとこ一家が三世代総出で来た)合計13人も集まったので、私はコミュ障を大いに発揮してしまうことに。
友達もちらほらめでたい話も(そしてそれとは別に大変そうな話も)聞こえてきて、なんだかしんみりするやら。
友人きっての願いでラーメンの山岡家に。「正月からすまん、でもどうしても食べたかったんだ」とのことで、まあ我々も久しぶりなので喜んでご一緒することに。
思ったよりも客が多い!
1月2日からやってるラーメン屋ということで需要が高かったのかもね。
においは以前の通りクセ強系だけど、こってりしていて美味しかったです。
それから業務スーパーで軽く買い出し、家で飲み会など。最近は友人の仕事の話を聞くのも割と楽しかったり。
その後、「千と千尋の神隠し」がテレビでやっていたので(実は通しで見たことがなかった)「いや面白いなこれ」とか話しながら見たり
(カオナシは私の中の「存在しない(?)妹」への憧憬みたいなものを描き出してるような気がした。千尋可愛すぎるだろ、あんなん恋するって)、
その後、友人の一人が買ってきてくれた「マリオパーティージャンボリー」をやったりして夜は更けていくのでした。
「えらんでブロックロード」が凄まじい神ゲーだった。ミクロな限定ジャンケン(?)気分。
なんだかんだで楽しい正月休みでしたが、情報量が多すぎて、最終的にヘンな夢を見ました……(w
「千と千尋」みたいな世界観の、しかしダンボールで出来た4畳半の建築(無限に高い)を、ほんの僅かな足場を使って、
登ったり降りたり……最終的に足場のアンカーがすっぽ抜けて、「うおおおお!」とダンボールの壁に蹴りを入れて突き破ってなんとか止まる、みたいな……。
Max9でまた遊んでいます。
VIDEO
poly~とかを触る前に、まずは基本を押さえようと思って、
チュートリアル
に回帰。
buffer~ と
cycle~を使ってウェーブフォームを繰り返すシンセを触ってみよ~と思ってやってはみるものの、
まだるっこしいというか、上手く切り抜けずガガガガッとなったので、むしろ波形を
gen~と数式で書いてみることに。
既にやっているJavaScriptでの数式シンセと似たような感じです。
gen~内の
in 1と
out 1はオーディオ信号の入出力を表している。消したら鳴らなくなる。
codebox内に数式を書いていく。sinだけじゃなくabsとかも効くので、全波整流を試す。
DC成分(定積分で出てくる値)が乗るので
dcblock~でカット……と思いきやNo
such object.(これは環境次第らしい)。 ならば
hip~ 5.(ハイパスフィルタ。周波数0Hz成分らしいのでこれで切れるらしい。ほえ~)でカット……と思いきや、
PureDataにはhip~があるけどMaxにはないらしく、
cross~とかを使って上手に組んでいく必要があるらしい。
そこまでいくと趣旨がずれるので、ChatGPTに聞いて
gen~内でDC処理については書いてもらってしまった。
っていうか
gen~を試そうとしたら最初半透明のウィンドウが出て来て、
あれ?と思ったらコンソールにbpatcher: error loading patcher
gen~とか出て来やがって、
調べたらMax9のインストールがうまくいっていなかったらしい。結局再インスコですた。zipもLhaplusだとうまく開かなかったし、
インストーラも空ディレクトリに展開する時に「なんかもうファイルあるけど」とか言ってくるし……。
まあ再インストールでちゃんと
gen~も復活したのでよし。
とにかくこれで(DSL導入とか調律法の導入とか必要かもしれないけど)まがりなりにも数式で波形を宣言してMax上で動かせるようになったってこと……?
……と言っても
まだポリシンセ化で引っかかってるのか。はは……。とにかく、次は変調あたりを試すかもしれません。それかJitコマンドあたりか。
2026年1月1日
あけましておめでとうございます。
今年もどうぞよろしくお願い致します。
VIDEO
Max/MSPで年越ししていました。「coll」という機能を使ってシーケンスを作ってみました。
metro と
counter 0 7で一歩一歩出力してます。
intで指定したmidinoteを
mtofで周波数に変換して、
cycle~で音波を作ると。
collは中身を開くのが最初わからなかったのですが、こっちはカギモードからダブルクリックで開ける。
あと
poly~に挑戦していたのですが、こっちはかなり厄介で今回は安定せず断念。
ものとしてはmaxpatで定義されたボイスを指定した数だけ同時に鳴らせるというものなのですが、
その定義が多分うまくいっていないんだと思います。
thispoly~というのを入れないといけないっぽい。
collの書き方も面倒くさくなってきますね。出来れば
counter -> collでまずカウンターとコードネームを紐付け、
それから
coll -> collでコードネームから3和音を引っ張ってくるとかが簡単なのかな。
でもボイシングとか考えるとやっぱりcoll一個で済ませるのが合理的になりそう。
っていうかまあ実用的にはMidiで打ち込んでしまったものをMax/MSPの
poly~で鳴らすとかが出来ると嬉しいのだけど。
というか今見るとチュートリアルをかなり飛ばしている。一歩一歩進めた方がいいんだろうな。変調器あたりから作りましょうか。
あと接尾辞(?)として
~がつくものはって何?
と思っていたら日記を書いているVSCodeが丁寧に教えてくれました。
オーディオ信号を扱うオブジェクトには
~がつくのだそうです。なるほどね。
AI補助を受けて日記を書いています(w
←2025年第四期 2026年第二期→