0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ReaScript(lua)でコード入力を楽にするスクリプトを作った。

Posted at

DAWにコードを入力するのはとても面倒。

コード(音楽的な)は3音~複数音による和音ですから当然その回数入力してやらないといけません。
また、コードにはメジャー、マイナーからはじまりもろもろ種類があります。
ピアノロールに打ち込むときに個人的にはどうもしっくりこない(コード主体の音楽をやってこなかったのもある)ので何か良い方法はないかとコードを入力するためのプラグインを導入してみたりもしたけれどいまいち便利ではありませんでした。

また、ギター譜などになるとそもそもコード名しか書いていないこともあり、コードになじみのない(理屈ではわかっている)人にとってはいいから楽譜に書いてくれ。となります。

ちょっとしたひらめき

どうにかしてコードを簡単に入力できないかと考えているうちにちょっとしたひらめきがありました。
midiのクリップに名前が付けられるのでそこにコード名などを入力してスクリプトで変換してやればいいんじゃないだろうか。と。

この時点ではReaScriptに何が出来るのかわかっていませんがluaは解ります。
じゃあAPIさえ分かればいけるのでは? と調査を開始しました。

試行錯誤

プロジェクトのなかのテイクの中のノート。のような階層であるとか、この辺りはSynthesizer Vなどでも気を付けないといけないところですがどういう概念で作られているDAWなのか探りながらやらないと要らない苦労をすることになるので柔軟に…。
引っかかりポイントとしてはテイクとクリップの開始時間のあたりです。
クリップ内であってもグローバル位置を持っていてそのグローバル位置を指定して作らないといけないなどは、言われてみればそうだな。という見落としがちな部分だったと思います。

  • テイクにノートをつくる
  • テイクの名前を取得する

この辺りが出来ればいけるだろうと弄っているとなかなかいい感じになったので一気に作業しました。

完成したスクリプト


-- 指定された take が MIDI かどうかを判定
function is_midi(take)
  return take and reaper.TakeIsMIDI(take)
end

-- 指定された take 内のすべての MIDI ノートを削除
function clear_take(take)
  if is_midi(take) then
    local note_count = reaper.MIDI_CountEvts(take)
    for idx = note_count - 1, 0, -1 do
      reaper.MIDI_DeleteNote(take, idx)
    end
    reaper.MIDI_Sort(take)
  end
end

-- 指定された位置にノートを1つ挿入
function make_note(take, start_pos, len, prop)
  if is_midi(take) then
    local pitch = prop.pitch or 60
    local velocity = prop.velocity or 100
    local chan = prop.chan or 0
    local selected = prop.selected or true
    local muted = prop.muted or false
    local start_ppq = reaper.MIDI_GetPPQPosFromProjTime(take, start_pos)
    local end_ppq = reaper.MIDI_GetPPQPosFromProjTime(take, start_pos+len)
    
    reaper.MIDI_InsertNote(take, selected, muted, start_ppq, end_ppq, chan, pitch, velocity, false)
  end
end

-- 文字列を区切り文字で分割する
function split(str, sep)
  local result = {}
  for match in (str .. sep):gmatch("(.-)" .. sep) do
    table.insert(result, match)
  end
  return result
end

-- 音名テーブルとコード定義
local notes = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"}
local chords = {
    ["M"] = {4, 7},
    ["m"] = {3, 7},
    ["7"] = {4, 7, 10},
    ["M7"] = {4, 7, 11},
    ["m7"] = {3, 7, 10},
    ["dim"] = {3, 6, 9},
    ["6"] = {4, 7, 9},
    ["aug"] = {4, 8},
    ["sus4"] = {5, 7},
  }
local prj = reaper.EnumProjects(-1) -- 現在のプロジェクトを取得
local items = reaper.CountSelectedMediaItems(prj) -- 選択中のメディアアイテムの数を取得

-- 各選択アイテムに対して処理を実行
for idx = 0, items - 1 do
  local item = reaper.GetSelectedMediaItem(prj, idx)
  local take = reaper.GetActiveTake(item)
  local retval, name = reaper.GetSetMediaItemTakeInfo_String(take, "P_NAME", "", false)
 
  local item_pos = reaper.GetMediaItemInfo_Value(item, "D_POSITION")
  local item_len = reaper.GetMediaItemInfo_Value(item, "D_LENGTH")
  
  -- 既存のノートをクリア
   clear_take(take)
  
  -- 名前(例:"C M")を分割して要素(音名やコード)を取得
  local elem = split(name, " ")
  local note_num = 60 -- デフォルトのMIDIノート番号(中央C)
   
  for i, e in pairs(elem) do
    -- route key
    for ni, n in pairs(notes) do
      if e == n then
        note_num = 59 + ni -- 59+C=60の中央Cを基準にして調整
      end
    end
    
    -- ルート音を挿入
    local prop = { pitch = note_num }
    make_note(take, item_pos, item_len, prop)

    -- コード名に一致したら対応するコード音を挿入
    for ci, c in pairs(chords) do
    if e == ci then
        for ni, note in pairs(c) do
          local prop = { pitch = note_num + note }
          make_note(take, item_pos, item_len, prop)
        end
      end
    end
  
  end
  -- 1アイテム分の処理完了
end

動作画面

普段luaのコードを出す必要はありませんが。
一応動かしてるんだぞっていうアピールのため。

midiクリップを選択してF2でアイテムプロパティを開き、名前に「C sus4」という感じでスペースで分けて入力してやります。1クリップに一種類だけです。
あとはスクリプトを実行すればそれぞれのクリップの長さ分のシーケンスが挿入されます。

これからの展開としてバッキング入力に変換できるようなものが出来れば便利かもしれません。

reaper

グロッサリー

クリップへの入力
「C sus4」など、基音とコードの種類を入力

基音

  • C
  • C#
  • D
  • D#
  • E
  • F
  • F#
  • G
  • G#
  • A
  • A#
  • B

コードの種類(他にも必要であればluaに追加してください)

  • M Major
  • m minor
  • 7
  • M7
  • m7
  • dim
  • 6
  • aug
  • sus4
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?