一緒に音楽を再生するコードをかき鳴らす



ステージの設定
私は、私がどのようにインターフェイスを構築したかについて話しましたSonic Pi 私が準備中だったときRubyConf 2020 ルビーの話Coverage モジュールです.そのポストの終わりに、我々は音の音に音を送ることができました.今日、我々のコードはギターを演奏して、アンプにそれらの音を送ります.

弦理論
ギターは弦楽器です、そして、彼らが遊ぶとき、それらのストリングの各々は音をたてます.この例では、ハッピーパスにフォーカスします.これは、文字列を摘むことが期待される注記を果たしていることです.私が構築したコードはまた、文字列が壊れていることを考慮し、壊れた文字列を再生しようとすると動作しません.この動画を見るfull implementation どのように動作するかを確認します.
個々の文字列をプルすると、新しい音が作成されます.
class String
  def pluck(fret:)
    ...
    play_note(fret)
  end

  private

  def play_note(fret)
    StringSound.new(
      string_number: @number,
      tuning_note: tuning_note,
      fret_number: fret,
    )
  end
end
The @number 変数はギターの上のどのストリングです、インデックス0が低Eであり、インデックス5が標準的なチューニングで高いEであることです.The tuning_note 任意の文字列を任意の音符にチューニングすることができますので、その文字列に調整されることに注意してください.再び、ここで単純さのために、我々は標準チューニング(EADGBE)を仮定します.
我々StringSound クラスはその情報をSonic Piに送るコマンドに変換します.ソニックパイのすべてのノートはnumber , また、シンボルとして渡される“伝統的な”ノート名を使用することもできます.私たちは
あなたがフレットを押すことなくそれを摘むならば、我々のストリングが演奏するメモを理解するために、それを使ってください.
class StringSound
  def playable_note_root
    playable_note_key.dig(@string_number, @tuning_note)
  end

  def playable_note_key
    {
      0 => { e: :e2 },
      1 => { a: :a2 },
      2 => { d: :d3 },
      3 => { g: :g3 },
      4 => { b: :b3 },
      5 => { e: :e4 },
    }
  end
end
音符の横の数2 イン:e2 低E文字列の場合はオクターブを表します.
ここで役に立つものは、メモがまだ音のパイに番号であるということです.我々は文字列のルートノートに文字列に押されたフレット番号を追加することができますし、ソニックパイは何が注意してください知っている.我々は、そのノートを再生するために私たちに送信する音のPIコマンドを構築します.
class StringSound
  def amp_value
    "(note(:#{playable_note_root}) + #{@fret_number})"
  end
end
これはすべての文字列(データ型であり、楽器の一部ではありません)です.なぜなら、私たちはsonic-pi-cli gem . これはnote ソニックパイでメソッドをシングルトーンを再生します.

一つのひもをつかむ
私たちのギタリストは、多くの弦の全体としてギターとのインタフェースです.彼らはまずギターの首に指を置きます.
class FingerPlacement
  attr_reader :fret
  attr_reader :string_number
end
そして、その配置で個々のストリングを引きます.
class Guitar
  def pick(finger_placement, duration: 1)
    result = strings[finger_placement.string_number].pluck(fret: finger_placement.fret)
    @amplifier.play(sound_output("play #{result.amp_value}", duration: duration))
  end
end
ここで我々のギターは、我々がソニックパイに送るコマンドに詳細を加えています.我々は、文字列から再生するには、ノートについての情報がありますが、今私たちはそれがギターからノートのように聞こえるようにしたいと私たちはギタリストにどのくらいの期間のためのメモを再生すると言うに依存します.
我々は、音を再生するときに使用するシンセサイザーを指定してソニックパイでこれを行うことができますし、我々はギターのように聞こえるものを選択します.
class Guitar
  def sound_output(play_operation, duration: 1)
    [
      "with_synth :pluck do",
      "#{play_operation}, release: #{duration}",
      "end",
    ].join("\n").strip
  end
end
ソニックパイのIDEで直接再生したいなら、もっと身近に見えます.
with_synth :pluck do
  play note(:e2 + 1), release: 1
end
しかし、我々はそれからソニックPI CLI宝石を通してその音を音のパイに送るために、ストリングでこれをすべて包む必要があります.
我々のアンプは、経由で渡され、その後、そのコマンドを受け取り、ソニックパイに送信、サウンドを生成!

心の琴線に触れる
ソニックパイはすでに再生する方法を知っているchords , それで、これは速いセクションでありえました;しかし、我々はその機能を少し違って複製するつもりです.私たちは、ストリングについて話すとき、私が言及した現実のためにこれをしています.ストリングが壊れているならば、ストリングが規則的に遊ぶコードで注意は聞かれてはいけません.
このように、我々は文字列を文字列に移動するためのメモを決定する必要があります.推論が壊れたストリングを扱うことになっているにもかかわらず、我々はこの説明でそのケースを考慮するつもりはありません.あなたはfull implementation それがどのように扱われるかを見ること.
まず最初にどのノートを再生するかを知る必要があります.
class Guitar
  def strum(chord, duration: 1)
    notes = [
      strings[0].pluck(fret: chord.first_fret),
      strings[1].pluck(fret: chord.second_fret),
      strings[2].pluck(fret: chord.third_fret),
      strings[3].pluck(fret: chord.fourth_fret),
      strings[4].pluck(fret: chord.fifth_fret),
      strings[5].pluck(fret: chord.sixth_fret),
    ].map(&:amp_value)
  end
end
その後、これらのノートのすべてを取るし、我々のアンプには、ソニックパイのを使用して渡すplay_pattern_timed method . これはまた、各音符の間に時間を定義することができますので、我々はすべての文字列全体でダウンストロークを完了するためにあなたの手を取る時間をシミュレートするためにそれぞれの間に少量の時間を置くことができます.
class Guitar
  def strum(chord, duration: 1)
    notes = [...].map(&:amp_value)

    @amplifier.play(
      sound_output(
        "play_pattern_timed [#{pattern_notes.join(", ")}], 0.05",
        duration: duration,
      )
    )
  end
end
0.05は、それがコードを再生するときに、次の1つの文字列から引き込むためにかかる時間の我々の量です.

ロックオン
いくつかのキーのソフトウェア設計の原則を組み合わせることで、私たちは、柔軟な、拡張可能な、テスト可能なシステムの音楽を再生するためのいくつかのブログの記事のコース上で作成することができた.
我々は今、それを介して我々のギターを介して渡されるとの通信方法を知っているアンプを装備している(しかし、正しい方法に注入されたクラスとしてどこにでもメモを送信することができます).私たちのギターは様々な文字列です.
私たちのバンドのための方法を知っているソングライターを考えれば、我々はsong が必要です.
あなたが密接に聞くならば:14、あなたはストリングブレークを聞くことができます.これらの原理においても、間違いと誤りが起こります.システムがフォールトトレラントな方法でエラーを処理する準備ができていることを確認してください.この探査で私に加わってくれてありがとう.

This post originally published on The Gnar Company blog.