概要
REAPERのプロジェクトタブを、WebブラウザみたいにCtrl+Tabでサクサク切り替えられたらな~~。
→ でもアクションリストにはなぜかそういうアクションが見当たらないんだよな~~。
→ よし作るか。
→ 作った。
→ あっよく見たらアクションリストに元からちゃんとそういうのあった。
→ 車輪の再発明おめでとう。永年車庫入り。死。
→ いや、死なすぐらいならReaScript基礎編記事としてQiitaにでも突っ込むか。←今ここ
実装
とりあえず一番のコア部分はこれ。
function SelectProjectTabByStep(step)
local function prj(i) return reaper.EnumProjects(i, "") end
local i, i_active = -1, -1
local prj_active = prj(-1)
repeat
i = i + 1
i_active = prj_active==prj(i) and i or i_active -- 今のプロジェクトが何番目のタブなのか把握
until not prj(i+1)
local i_max = i
local i_new = (i_active+step) % (i_max+1) -- インデックス外なら回り込む
reaper.SelectProjectInstance(prj(i_new))
end
使ったReaScript関数は2つ。
- reaper.EnumProjects
- reaper.SelectProjectInstance
reaper.EnumProjects
ReaProject retval, string projfn = reaper.EnumProjects(integer idx, string projfn)
idx=-1 for current project,projfn can be NULL if not interested in filename. use idx 0x40000000 for currently rendering project, if any.
idx
に何番目のプロジェクトかを指定すると、ReaProject
とかいうデータ型(内蔵デバッガの表示はreaper object
)でそのプロジェクトが帰ってくる。
インデックスは一番左のタブから0始まりで数え、また特別に現在開いているプロジェクトは-1
で指定できる。…というか、インデックス範囲より上だったり下だったりするような、はみ出した数を入れたらとにかく現在のものになるっぽい。なのでインクリメントして端まで達しても勝手に回り込んだりはしてくれない。あと少なくとも整数型である必要があるらしく、色々試したけど整数以外はエラーになった。
-- 上記のような状態で、
prj = reaper.EnumProjects(-1, "") -- 現在のタブ(2個目のタブ)
prj = reaper.EnumProjects(0, "") -- 1個目のタブ
prj = reaper.EnumProjects(-3776, "") -- 現在のタブ(-3775個目のタブは無いので)
prj = reaper.EnumProjects(3.14, "") -- "number has no integer representation"
prj = reaper.EnumProjects("Mt.Fuji", "") -- "number expected, got string"
prj = reaper.EnumProjects(nil, "") -- "number expected, got nil"
projfn
はファイル名だけど今回は関係ない。
なおリファレンスにはprojfn can be NULL
とあるが、少なくとも文字列型になり得る値である必要があるらしく、サボったりnil
にしたりするとエラーになった。
prj = reaper.EnumProjects(-1, "") -- OK
prj = reaper.EnumProjects(-1, 3776) -- OK
prj = reaper.EnumProjects(-1) -- "string expected, got no value"
prj = reaper.EnumProjects(-1, nil) -- "string expected, got nil"
reaper.SelectProjectInstance
reaper.SelectProjectInstance(ReaProject proj)
REAPERのプロジェクトを指定するとそのインスタンスを開く。
なお、ReaScriptでは何をするにしてもほぼ必ずこのReaProject
を指定する。というか、例えばメディアをいじるためにはまずそのメディアの取得が必要になり、そのためにはそのメディアがあるトラックを取得し、そのためにはそのトラックがあるプロジェクトを取得……という感じで、何をするにも結局親玉のプロジェクトを掴んでやらないことには始まらない仕組みになっている。気がする。
で、実際そのためにいちいちReaProject
型データを頑張って掴むのはめんどいので、特別に0
を入れてやると自動的に現在のアクティブなプロジェクトを指定することができるようになっている。例えばプロジェクトのメディアアイテム数を数えるreaper.CountMediaItems
の説明を見ると、
integer reaper.CountMediaItems(ReaProject proj)
count the number of items in the project (proj=0 for active project)
とある通り、便利。
…色々試したところ、実は0
に限らず割とどんな雑な値でもとにかく現在開いているプロジェクトが指定されるっぽい。まあ0
にせよと言われてるんだから素直にそうすれば良いんだけど。
i = reaper.CountMediaItems(reaper.EnumProjects(0, "")) -- 1個目のタブ
i = reaper.CountMediaItems(0) -- 現在のタブ(推奨)
i = reaper.CountMediaItems(3776) -- 現在のタブ
i = reaper.CountMediaItems(3.14) -- 現在のタブ
i = reaper.CountMediaItems("Mt.Fuji") -- 現在のタブ
i = reaper.CountMediaItems(nil) -- 現在のタブ
i = reaper.CountMediaItems() -- 現在のタブ
あと、このproj=0 for active project
という説明は、必ずしも全てのReaProject
型引数を要する関数の説明に書かれているわけでもなければ、基礎事項としてリファレンス全体の頭とかに書かれているわけでもない。
なので、うっかりド忘れすると困る(困った)。今回のreaper.SelectProjectInstance
の項目にもそういう説明はないため、あらかじめ知っておく必要がある。
参考までに、Chromeで開いたLua版リファレンスページ内を0 for active project
で検索したら結果は10件、ReaProject proj
で検索したら106件だった。
つまり、ReaProject
型の引数を要するAPIが106件あって、その中で上記の「0
にすれば済むよ」という話を説明してくれているのは10件だけということ。頑張ろう。
あとは書く
REAPERリソースフォルダ(REAPER.ini
があるフォルダ)のScript
フォルダ内に自分用のフォルダPhroneris
(私の横文字HNです)を作り、更にその中にlib
フォルダを作って複数のスクリプトで共用するスクリプトの置き場とした。
function SelectProjectTabByStep(step)
local function prj(i) return reaper.EnumProjects(i, "") end
local i, i_active = -1, -1
local prj_active = prj(-1)
repeat
i = i + 1
i_active = prj_active==prj(i) and i or i_active -- 今のプロジェクトが何番目のタブなのか把握
until not prj(i+1)
local i_max = i
local i_new = (i_active+step) % (i_max+1) -- インデックス外なら回り込む
reaper.SelectProjectInstance(prj(i_new))
end
そして以下の2つをアクションから読み込んでショートカットを割り当てて完了。
あっそうそう、lib
からスクリプトを引っ張ってくるためにreaper.GetResourcePath
でREAPERのリソースフォルダのパスを取得する。
-- こいつにCtrl+Tabを割り当て(既存の重複ショートカットは解雇)
package.path = reaper.GetResourcePath().."\\Scripts\\Phroneris\\lib\\?.lua"
require "Select project tab"
SelectProjectTabByStep(1)
-- こいつにCtrl+Shift+Tabを割り当て(既存の重複ショートカットは解雇)
package.path = reaper.GetResourcePath().."\\Scripts\\Phroneris\\lib\\?.lua"
require "Select project tab"
SelectProjectTabByStep(-1)
ちなみに実際のコードには日本語コメントは一切含めていない。REAPERのスクリプトエディタは、マルチバイト文字(非ラテン文字?)をまともに表示できないので…。
成果
(キー入力表示:tinyosdkey)
作った動機と顛末
あれは、自作の製品版REAPER日本語化パッチ(森)がver 5.70.001の頃――
「REAPERのプロジェクトタブを、WebブラウザみたいにCtrl+Tabでサクサク切り替えられたらな~~」
「まあ普通に考えてそんな基礎的なアクションはまず間違いなく内蔵してるはずだから、探してショートカット割り当てれば良いよな。アクションリストで…next tab
っと」
「…? Docker:
っつってるしこれはドックの方のタブだよね。こんだけ?」
「え、じゃあtab
ならタブ関連の全部のアクションが出るかな」
「……??」
「プロジェクトタブの切り替え、無いの???????」
「まあ……無いなら作るか」
そして完成。
「できた~。さて、それはそれとしてREAPER日本語化パッチの翻訳も進めるか」
「おや? 気になるブログが」
「ん~なになに、現行の日本語化パッチではアクションリストが中途半端にローカライズされるので内蔵アクションを探し難くなる…?」
「…………」
(日本語化パッチver5.70.002で英語検索に対応させました)
おしまい。
執筆時点の環境
- Windows 7 64bit
- REAPER v5.78/x64, v5.79pre7/x64
- REAPER APIリファレンス Generated by REAPER v5.70/linux-arm
リンク
REAPER | ReaScript
REAPER API functions
REAPERの日本語化パッチのお話 : ペロリーパー | PeloREAPER
製品版REAPER日本語化パッチ(森)