プログラマーのための音楽理論

2026/09/03 5:19

プログラマーのための音楽理論

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

デジタルサウンドは、高いサンプリングレート(例:1 秒間に 44,000 回)で物理的な空気圧を数値データに変換し、スピーカーの位置を表します。単純な正弦波が存在する一方で、実在の楽器は調和系列によって複雑な音色を生み出します。ピッチの関係は対数的であり、周波数を 2 倍にするとオクターブとなり、不協和音は調和基本波の間にわずかにずれた周波数によるビートが生じることで生じます。ピタゴラスのコーマのような数学的矛盾を解決するために、システムはオクターブを 12 個の一致するステップに分割して全てのキーで演奏可能にする等律調律を採用します。標準化されたフレームワークがこれらの複雑さを管理します:MIDI は注記 69 を基準周波数として固定し、任意のピッチを計算するための汎用周波数公式を定義し、楽譜は音程を全音階軸上でシリアライズし、臨時記号と期間を表す 2 の累乗を用います。さらに、音楽構造はメジャー・スケールや第 3 を積み重ねて作られた和音の特定の間隔パターンによって定義され、ローマ数字分析法を用いることで、固定されたピッチではなく調内での級に対する和音を記述することで転調が容易になります。

本文

物理法則と算術による音楽の原理:ゼロからコードで理解する

楽器演奏は困難な挑戦ですが、「正しい音」とはなぜ「正しく」なのかという根本的な理由を理解することはできません。従来の説明では慣例や暗記が強調されがちですが、音楽には物理法則と数学的根拠に基づいた明確なシステムが存在します

この文章では、ゼロから基本原理をコード(JavaScript)で実装し、十二平均律、音階、コード進行、記譜法までを数理的に導出する方法を示します。楽器も「信仰」も不要です。すべては数値の時間変化と物理現象に過ぎません


1. 音とは何であるか

音の本質

  • 音は空気の圧力の揺らぎであり、スピーカーコーンの往復運動によって発生します。
  • コンピュータ上のオーディオ処理とは、「コーンがどの位置にあるか」を表す数値のリストを生成することです。
    • サウンドカードは毎秒 44,000 回(サンプリングレート) この数値を更新します。
    • 音声ファイルは記録されたデータ、シンセサイザーはリアルタイムで生成したデータです。

コードによる音の生成

最も単純な「サイン波」を用いて、毎秒 440 回の振動(周波数)を発生させます。

const ctx = new AudioContext();
const out = ctx.destination;
const osc = ctx.createOscillator();
osc.frequency.value = 440; // 周波数:Hz (ヘルツ)
osc.connect(out);
osc.start();
osc.stop(ctx.currentTime + 1);

重要なポイント

  • 440Hz は恣意的な基準(ラ)であり、システム全体のピッチフォークです。これを
    300
    に変えれば異なる高さの音になりますが、オシレーター自体は「音符」という概念を持っていません。単に「一秒間に何回振動するか」だけが事実です。
  • 周波数は音高(ピッチ)を表します。数値が高いほど音が高音になります。

2. 音楽的な音を創出する(エンベロープ)

クリック音の問題

オシレーターを単純に停止すると、波形が極端な位置で切り取られ、物理的な圧力変化として「パチッ」というクリック音が鳴ります。

解決策:エンベロープ(音量包絡線)

音を滑らかにするために、時間とともに変化する音量を追加します。これを音楽では「エンベロープ」と呼びます。

  • アタック (Attack): 0 秒で無音 → 0.01 秒で最大音量へ急上昇。
  • デケイ (Decay): その後ゆっくりとほぼゼロまで減衰。
// ヘルパー関数:周波数、開始時間、長さ、波形種別を指定して音を作成
function note(freq, start = 0, length = 0.5, type = "sine") {
  const t = ctx.currentTime + start;
  const osc = ctx.createOscillator();
  const env = ctx.createGain();

  // オシレーター設定
  osc.type = type;
  osc.frequency.value = freq;

  // エンベロープ設定 (ADSR)
  env.gain.setValueAtTime(0, t);                      // アタック前:無音
  env.gain.linearRampToValueAtTime(0.3, t + 0.01);    // アタック:0.01 秒で最大へ
  env.gain.exponentialRampToValueAtTime(0.001, t + length); // デケイ:滑らかにフェードアウト

  osc.connect(env).connect(out);
  osc.start(t);
  osc.stop(t + length);
}
  • 音色の決定要因: ピッチ(周波数)だけでなく、主にこのエンベロープが音符の性格を決定づけます。アタック時間を長くすればドラムのような打撃音から、弓引きのような擦れ音へ変化します。

調和系列(ハーモニック)

サイン波は単一周波数ですが、実際の楽器は基本音倍音が同時に振動しています。これらを「調和系列」と呼びます。

  • バイオリン:基本音 (220Hz) とその整数倍 (440, 660, 880...) が複雑に重なっています。
  • 音色の秘密: ハーモニックの**相対的な強さ(レシピ)**の違いが、楽器同士の区別になります。
    • sine
      :単一周波数(検査音源)。
    • triangle
      /
      square
      /
      sawtooth
      :ブラウザ標準の波形種類。
// 異なる波形を鳴らしてみる
["sine", "triangle", "square", "sawtooth"].forEach((type, i) => {
  note(220, i * 0.7, 0.6, type);
});

3. 周波数とピッチの法則

オクターブ(倍増)の不思議

周波数を 2 倍にすると、音楽的には「同じ音符(高いオクターブ)」として認識されます。

  • 音高は乗法的である: 「足す」のではなく「掛ける」ことで八度を上がります。
    • $110 \to 220$ と $880 \to 1760$ の感覚的距離は同じです。
  • 対数的空間: 音楽の音高空間は線形ではなく、周波数の比(レシオ)で表されます。

二つの黄金則

  1. 音高は比:八度アップ = ×2。
  2. 一オクターブ:倍増して元の音に戻れるため、すべてのピッチ問題は「ある周波数とその 2 倍の間の空間」をどう分割するかという問題に還元されます。

4. 良い響きを生む比率(純正律)

人間は周波数のすべてを均等には区別せず、単純な比を持つ間隔が安定して聞こえます(協和音)。

  • 良い響きの例:
    • 2/1: オクターブ
    • 3/2: 純正五度(最も重要な比率)
    • 4/3: 純正四度
    • 5/4: 長三度
  • 悪い響きの例:
    • 16/15: セミトーン(不安定)
    • √2 (無理数): 車のアラームのような音

物理的な理由:ビート現象

二つの音が一致しない場合、位相がずれたことで音量の脈動(ビート)として耳に聞こえます。

  • 協和音: ハーモニック(倍音)が完全に重なり合い、周期的なパターンをすぐに作ります。
  • 不協和音: ハーモニックが一致せず、複雑な干渉を生じます(例:√2 の比率)。
// 五度 (3/2) を重ねてみる
const pureFifth = (3 / 2); // 純正五度
console.log("純正五度の比率:", pureFifth);

5. ピタゴラスマと十二平均律

バグ:ピタゴラスマ

「純粋な五度(3/2)」を 12 回積み重ねると、オクターブの正確な倍率($2^7$)にはなりませんでした。

  • ピタゴラスマ: $1.0136$ 倍の隙間が発生します(約 23 セント)。これを補正しないと音楽は回りません。
  • 理由: $3^{12} \neq 2^7$。素数である 3 と 2 は同じべき乗にはなりません。

解決策:平均律

現代の音楽が採用しているのは、妥協です。

  1. オクターブ(構造的に完璧)を 12 等分します。
  2. その残りの間隔はすべて近似値とします。
  3. この「半音」は
    2
    1/12
    乗根 (
    Math.pow(2, 1/12)
    ) です。
// 十二平均律の半音率
const semitone = Math.pow(2, 1 / 12);
console.log("1 セミトーン:", semitone.toFixed(4));

// オクターブを 12 ステップで完璧に回る確認
let freq = 220;
for(let i=0; i<12; i++) {
  freq *= semitone;
}
console.log("12 ステップ後の周波数:", (freq/220).toFixed(4)); // 約 2.0000

MIDI ノンバーリング:整数化された音符

平均律を導入した結果、すべてのピッチは整数化されました。

  • 基準: MIDI 番号
    69
    440Hz
    (ラ) です。
  • 変換式: $f(n) = 440 \times 2^{(n-69)/12}$
const midiToFreq = (n) => 440 * Math.pow(2, (n - 69) / 12);

// 例:MIDI 番号から周波数を計算
console.log("MIDI 60 (中央 C):", midiToFreq(60).toFixed(2));
console.log("MIDI 69 (La):", midiToFreq(69).toFixed(2));

6. 音階は「隙間のリスト」である

なぜ 12 つの音符か?

  • 12 を順番に弾くと音楽的ではありません。
  • 西洋音楽では、12 のうち 7 つを選んで不均衡な間隔(ステップ)を作ります。
  • **音階は「隙間のリスト」**です。
const buildScale = (root, steps) => {
  let notes = [root];
  steps.forEach(step => notes.push(notes[notes.length - 1] + step));
  return notes;
};

// メジャー音階のパターン:[2, 2, 1, 2, 2, 2, 1] (半音数)
const cMajorSteps = [2, 2, 1, 2, 2, 2, 1];
const cMajor = buildScale(60, cMajor);

メジャーとマイナーの違い

  • 同じ 7 つの音符を使っても、ステップの並び替えだけで全く異なる感情になります。
    • メジャー (Ionian):
      [2, 2, 1, 2, 2, 2, 1]
      → 明るい。
    • 自然マイナー (Aeolian):
      [2, 1, 2, 2, 1, 2, 2]
      → 悲しい。
  • これらはモード(モード)と呼ばれ、同じ配列を回転させたものです。
const majorSteps = [2, 2, 1, 2, 2, 2, 1];
// ローマン数字 I-VII を生成
const scale = buildScale(60, majorSteps);

// コード(トリアド)の構成:[ルート、三度 (ステップ+2)、五度 (ステップ+4)]
const triad = [scale[0], scale[2], scale[4]];

7. コードとコード進行

トリアド(和音)とは

  • 定義: スケール上で隔たった音符(3 つ離れている = 三度)を重ねたもの。
  • 安定性: 調和系列が重なるため、非常に響きます。
    • メジャー:
      [0, 4, 7]
      (半音間隔)
    • マイナー:
      [0, 3, 7]
  • 感情の違い: 中間の音を半音変えるだけで、メジャー ↔ マイナーが切り替わります。

セブンスコード

三度の上にさらに三度を積み上げるとセブンスコードになり、より複雑な響きと機能を持ちます。

  • メジャーセブンス
    [0, 4, 7, 11]
    : ジャズカフェ風。
  • ドミナントセブンス
    [0, 4, 7, 10]
    : 解決を強く促す

ローマン数字と相対アドレス

コード進行は絶対的な周波数ではなく、**スケール上の位置(ローマン数字)**で記述されます。

  • I V vi IV
    ii V I
    はどのキーでも同じ形状です。
  • 移調するには単に基準音をずらすだけで、進行の論理は不変です。
const chordsInKey = (root) => {
  const scale = buildScale(root, [2, 2, 1, 2, 2, 2, 1]).slice(0, 7);
  return (degree) => {
    // ローマン数字から実際の MIDI ノートへの変換
    const notes = [0, 2, 4].map((step) => {
      const i = degree - 1 + step;
      return scale[i % 7] + Math.floor(i / 7) * 12;
    });
    return notes;
  };
};

// 進行:I -> V -> vi -> IV
const progression = [0, 4, 6, 3]; // C メジャーの場合 (C, G, Am, F)

8. 緊張と解放(コード進行の原理)

音楽とは、「到達した」と感じる場所と「疑問符」を置いた場所を配置する技術です。

なぜ V → I が強力か?

  1. 導音 (Leading Tone): V コードには I のルートより半音低い音が含まれ、「目的地への扉叩き」のように働きます。
  2. トリトーン: ドミナントセブンスに含まれる不協和な間隔(6 セミトーン)。I への移動時、両方の音が逆方向に解決します(緊張の緩和)。

コード進行のデザイン

  • 1 (I) で終わる: 完成感。
  • 5 (V) で終わる: 続きがある。
  • 4 (IV) や 6 (vi) で終わる: 不安定、解決していない。
// I V vi IV は最も一般的でポップな進行の一つ
const popProgression = [1, 5, 6, 4]; 

9. 記譜法とは何か?

前述の原理(整数の配列と周波数の計算)だけで十分ですが、伝統的な五線譜も存在します。

  • シリアライズ形式: 古い技術であり、人間が即座に視覚化できるように設計されています。
  • ダイアトニック軸: 白鍵(メジャーな音符)を基準線とし、黒鍵はオフセットとして表現されます。
  • 臨時記号 (シャープ/フラット): エスケープ文字のような役割で、キーの定義やピッチの変更を視覚化します。
  • 節拍: 2 の累乗(1, 1/2, 1/4, 1/8...)で表現され、時間を効率よく保存しています。
    • .
      (ドット) は長さの増加を表し、二進法に基づく計算です。

結論:理論はすべてコード化できる

ここまでで導出したすべての概念(キー、スケール、コード進行、テンポ)を約 40 行の JavaScript で表現可能です。「暗記すべき trivia」ではなく、エンジニアリングとしての音楽が明らかになりました。

  • 十二平均律: 2 と 3 のべき乗の妥協。
  • 音階: 耳に識別可能な隙間のサブセット。
  • コード: 調和列が重なる安定した集合体。
  • 記譜法: 情報を保存・伝達するための古くからの形式。

これらはすべて長年月を経て最適化されたエンジニアリングの決定です。なぜなら、音楽には明確な物理的・算術的な理由があるからです。


お勧め資料

さらに深く学びたい方へ:

  • : 『Music Theory for Nerds』(著者:Eevee)。理論を論理的に理解したい必読書。
  • ツール: LightNote。Web 上で動作する美しいオーディオエディタ。
  • ドキュメント: MDN Web Audio API。依存関係なくブラウザで動く純粋な JavaScript 例が豊富。

同じ日のほかのニュース

一覧に戻る →

2026/09/07 5:45

Show HN:Mador(80行のProxy State Tuple で、あらゆる DOM をリアクティブにします)

## Japanese Translation: **改善済み。** 元のサマリーは正確ではあったが、開発者がライブラリの安全性と効率性を評価する上で価値のある具体的な行動詳細(`write` を通じたバッチ処理および自動的なクリーンアップ)を見落としており、また重要なポイントで言及されていた MIT ライセンスについても欠けていた。 以下に、これらの欠落している要素を取り入れた改善版を示す: ## 改善されたサマリー Mador.js は、重いフレームワークを採用することなく、複雑なビルド手順も必要とせずにリアクティビティを必要とする開発者向けの軽量な代替手段を提供する。従来のコンポーネントや仮想 DOM に依存するシステムとは異なり、このネイティブ ES モジュールランタイムは、独自の 3 つパートのバインディングパターン(要素の選択、更新関数の定義、ステート依存関係の指定)を用いて、状態を既存の HTML エレメントに直接バインドする。最小限のフットプリント(約 855 バイト)により、依存関係を知的に追跡して変更があった際のみ特定のプロパティを実行し直すことで、高速なパフォーマンスを実現する。状態の更新は `write` メソッドを通じられ、1 つの操作内で複数の変更をバッチ化する。特に重要なのは、Mador が要素が存在しなくなったときにランナーを自動的に削除することで、DOM のライフタイムを管理し、手動でのクリーンアップの必要をなくしている点である。このアプローチにより、npm または CDN を通じて直ちにレガシーコードベースに統合でき、下のレイヤーの DOM 構造を変更することなく、コンポーネントのライフサイクルも管理せずに済む。MIT ライセンスの下でリリースされたこの技術は、ステート管理を必要とするがフルアプリケーションフレームワークのアーキテクチャ的なオーバーヘッドを拒否するインタラクティブなページ機能を作成する際、特に価値があり、クイックプロトタイピングおよび定義された HTML 構造を持つプロジェクトへの動的な振る舞いのシームレスな追加を可能にする。

2026/09/06 20:56

インテリジェント・フライが開く(2025)

## Japanese Translation: 主要な警告は、ユーザーが LinkedIn の投稿作成に大規模言語モデル (LLM) に依存することをやめるべきであるという点にあります。この慣行は本質的に本物性を損なうためです。AI は編集やブレインストーミングの手助けにはなりますが、著者の真の声とは複製できません。その代わり、AI が生成したコンテンツは、過度な絵文字、短すぎる段落、およびダッシュの過剰使用といった不快なスタイルの特徴を示すことがよくあります。これらの明確なパターンにより、読者は投稿が本物の考えを反映したものではなく作りものであることを簡単に検出し、その結果、オーディエンスとの間に乖離が生じ、信頼を失い、完全に関与しなくなります。この批判は、LinkedIn が組み込みの「再書き換え」機能を通じて AI の使用を積極的に推進しているにもかかわらず発生しています。著者が引き続き AI の利便性をオリジナルの内容よりも優先し続ける場合、読者は不信感の高まりからコンテンツをスルーしたり見送ったりする可能性が高まります。したがって、ユーザーは意図したオーディエンスを失い、個人ブランドを損なうリスクに直面し、企業側がこの行動を促進する場合は、業界内の関与低下と信頼喪失を招く可能性があります。

2026/09/06 16:21

Isar Aerospace、2 度目の飛行で軌道到達とペイロード展開に成功

## Japanese Translation: Isar Aerospace は、欧州初の商業エンティティとして衛星を軌道に成功投入し、新たな商業ルートを通じて主権空間アクセスを提供する上で画期的な瞬間を刻みました。この実績は、2026年9月5日にノルウェー・アンドョアで離陸した「Onward and Upward」というミッション(同プログラム第2飛行)において確認されました。このミッションはすべての必要な技術的マイルストーンを実行しました:MaxQ通過、MECO完了およびステージ分離、第2段点火、100kmのカルマン線 crossing、ペイロードフェアリングの抛弃、円形化燃焼、ならびに教育用およびスタートアップ用ペイロードとの成功した分離を実施しました。これらのペイロードは、ESA Boost! の資金提供を受けてドイツ宇宙機関(DLR)の Microlauncher Competition で選定されました。2018年にミュンヘンの近くで設立された Isar は垂直統合を維持しており、小型および中型衛星に対する衛星作成、テスト、打上げサービスのほぼすべての側面を自社工場で行っています。この加速アプローチにより、通常は数十年にわたる開発期間をわずか数年に圧縮しました。展望としては、同社は地球観測や通信において重要な中傾角から高傾角軌道をサポートするためにカナダ・ノヴァスコシア州で新しい打上げ複合施設を建設し、「Spectrum」というロケットファミリー車両を年間最大40発の打ち上げに対応する専用施設で製造することで足跡を拡大しています。これらの進歩は、信頼性の高い欧州打上げサービスを求める商業顧客や機関に対して真の代替手段を提供します。

プログラマーのための音楽理論 | そっか~ニュース