107 lines
4.4 KiB
PowerShell
107 lines
4.4 KiB
PowerShell
<#
|
|||
|
|
MIDI Grid installer.
|
||
|
|
|
||
|
|
Registers the scripts as Reaper actions and binds them, by editing
|
||
|
|
reaper-kb.ini directly. This is done rather than via "Import key map"
|
||
|
|
because Reaper's importer silently converts unresolved script bindings
|
||
|
|
into "No-op (no action)" entries -- see README, Installation notes.
|
||
|
|
|
||
|
|
REAPER MUST BE CLOSED. It rewrites reaper-kb.ini on exit and will
|
||
|
|
discard anything written while it is running.
|
||
|
|
|
||
|
|
Usage: powershell -ExecutionPolicy Bypass -File install.ps1
|
||
|
|
powershell -ExecutionPolicy Bypass -File install.ps1 -Uninstall
|
||
|
|
#>
|
||
|
|
[CmdletBinding()]
|
||
|
|
param(
|
||
|
|
[string] $ScriptDir = $PSScriptRoot,
|
||
|
|
[string] $ResourcePath = "$env:APPDATA\REAPER",
|
||
|
|
[switch] $Uninstall
|
||
|
|
)
|
||
|
|
|
||
|
|
$ErrorActionPreference = 'Stop'
|
||
|
|
|
||
|
|
$kb = Join-Path $ResourcePath 'reaper-kb.ini'
|
||
|
|
if (-not (Test-Path $kb)) { throw "reaper-kb.ini not found at $kb" }
|
||
|
|
|
||
|
|
if (Get-Process reaper* -ErrorAction SilentlyContinue) {
|
||
|
|
throw "REAPER is running. Close it completely and run this again."
|
||
|
|
}
|
||
|
|
|
||
|
|
# id, section, description, script filename
|
||
|
|
$actions = @(
|
||
|
|
@('RSmidigrid_open', 0, 'MIDI Grid: Open selected item in grid mode', 'MidiGrid_OpenInGrid.lua'),
|
||
|
|
@('RSmidigrid_daemon', 0, 'MIDI Grid: Preview daemon (auto-started)', 'MidiGrid_Daemon.lua'),
|
||
|
|
@('RSmidigrid_mode', 32060, 'MIDI Grid: Toggle grid mode', 'MidiGrid_ToggleMode.lua'),
|
||
|
|
@('RSmidigrid_left', 32060, 'MIDI Grid: Cursor left one cell', 'MidiGrid_Left.lua'),
|
||
|
|
@('RSmidigrid_right', 32060, 'MIDI Grid: Cursor right one cell', 'MidiGrid_Right.lua'),
|
||
|
|
@('RSmidigrid_up', 32060, 'MIDI Grid: Pitch up one scale degree', 'MidiGrid_Up.lua'),
|
||
|
|
@('RSmidigrid_down', 32060, 'MIDI Grid: Pitch down one scale degree', 'MidiGrid_Down.lua'),
|
||
|
|
@('RSmidigrid_cell', 32060, 'MIDI Grid: Toggle note at cursor cell', 'MidiGrid_ToggleCell.lua'),
|
||
|
|
@('RSmidigrid_hold', 32060, 'MIDI Grid: Toggle hold mode', 'MidiGrid_ToggleHold.lua'),
|
||
|
|
@('RSmidigrid_audit', 32060, 'MIDI Grid: Repeat current cell', 'MidiGrid_AuditionCell.lua'),
|
||
|
|
@('RSmidigrid_scale', 32060, 'MIDI Grid: Set root and scale', 'MidiGrid_SetScale.lua')
|
||
|
|
)
|
||
|
|
|
||
|
|
# flags, keycode, section, id
|
||
|
|
# flags: 1 base, +4 Shift, +8 Ctrl, +16 Alt
|
||
|
|
# section: 0 = Main, 32060 = MIDI Editor
|
||
|
|
$keys = @(
|
||
|
|
@(21, 71, 0, 'RSmidigrid_open'),
|
||
|
|
@(17, 71, 32060, 'RSmidigrid_mode'),
|
||
|
|
@(1, 32805, 32060, 'RSmidigrid_left'),
|
||
|
|
@(1, 32807, 32060, 'RSmidigrid_right'),
|
||
|
|
@(1, 32806, 32060, 'RSmidigrid_up'),
|
||
|
|
@(1, 32808, 32060, 'RSmidigrid_down'),
|
||
|
|
@(1, 13, 32060, 'RSmidigrid_cell'),
|
||
|
|
@(17, 72, 32060, 'RSmidigrid_hold'),
|
||
|
|
@(17, 65, 32060, 'RSmidigrid_audit'),
|
||
|
|
@(17, 83, 32060, 'RSmidigrid_scale')
|
||
|
|
)
|
||
|
|
|
||
|
|
$backup = "$kb.midigrid-backup"
|
||
|
|
if (-not (Test-Path $backup)) {
|
||
|
|
Copy-Item $kb $backup
|
||
|
|
Write-Host "Backed up original to $backup"
|
||
|
|
}
|
||
|
|
|
||
|
|
$lines = [System.Collections.Generic.List[string]]::new()
|
||
|
|
$lines.AddRange([System.IO.File]::ReadAllLines($kb))
|
||
|
|
|
||
|
|
# Drop any previous MIDI Grid lines so re-running is idempotent.
|
||
|
|
for ($i = $lines.Count - 1; $i -ge 0; $i--) {
|
||
|
|
if ($lines[$i] -match '(?i)RSmidigrid') { $lines.RemoveAt($i) }
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($Uninstall) {
|
||
|
|
[System.IO.File]::WriteAllLines($kb, $lines, (New-Object System.Text.UTF8Encoding($false)))
|
||
|
|
Write-Host "Removed MIDI Grid actions and bindings."
|
||
|
|
Write-Host "Note: keys it had taken over (arrows, Enter) are now unbound in the"
|
||
|
|
Write-Host "MIDI editor. Rebind them, or restore $backup."
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
foreach ($a in $actions) {
|
||
|
|
$path = Join-Path $ScriptDir $a[3]
|
||
|
|
if (-not (Test-Path $path)) { throw "Missing script: $path" }
|
||
|
|
$lines.Insert(0, ('SCR 4 {0} {1} "{2}" {3}' -f $a[1], $a[0], $a[2], $path))
|
||
|
|
}
|
||
|
|
|
||
|
|
# KEY lines reference the *named command*, which is the SCR id with a
|
||
|
|
# leading underscore. Without it Reaper cannot resolve the binding and the
|
||
|
|
# key silently does nothing.
|
||
|
|
foreach ($k in $keys) {
|
||
|
|
$new = 'KEY {0} {1} _{3} {2}' -f $k[0], $k[1], $k[2], $k[3]
|
||
|
|
$pat = '^KEY {0} {1} \S+ {2}(\s|$)' -f $k[0], $k[1], $k[2]
|
||
|
|
$found = $false
|
||
|
|
for ($i = 0; $i -lt $lines.Count; $i++) {
|
||
|
|
if ($lines[$i] -match $pat) { $lines[$i] = $new; $found = $true; break }
|
||
|
|
}
|
||
|
|
if (-not $found) { $lines.Add($new) }
|
||
|
|
}
|
||
|
|
|
||
|
|
[System.IO.File]::WriteAllLines($kb, $lines, (New-Object System.Text.UTF8Encoding($false)))
|
||
|
|
|
||
|
|
Write-Host "Installed $($actions.Count) actions and $($keys.Count) key bindings."
|
||
|
|
Write-Host "Start REAPER, select a MIDI item, and press Alt+Shift+G."
|