Skip to content

Instantly share code, notes, and snippets.

@ftsf
Created January 27, 2022 08:39
Show Gist options
  • Save ftsf/5bde507d79298d8cd7097623a59712b4 to your computer and use it in GitHub Desktop.
Save ftsf/5bde507d79298d8cd7097623a59712b4 to your computer and use it in GitHub Desktop.
Synthesizer V - Transpose In Key Script
function getClientInfo()
return {
name = "Transpose In Key",
author = "impbox",
versionNumber = 1,
minEditorVersion = 0
}
end
function getTranslations(langCode)
-- please help add translations <3
return {}
end
-- Wrapper function to know the flow of code
function main()
--[[
1st check user inputs
2nd start a core routine
3rd end plugin
]]
if validateBeforeStarting() then
local formResult = SV:showCustomDialog(makeForm())
if (formResult.status) then
coreRoutine(formResult)
end
end
SV:finish()
end
-- Validate user request
function validateBeforeStarting()
-- if selected notes is empty, show message box and finish
if #SV:getMainEditor():getSelection():getSelectedNotes() < 1 then
SV:showMessageBox(SV:T("Selected Notes is Empty"), SV:T("You have to select at least one note."))
return false
end
return true
end
-- create custom dialog form
function makeForm()
local form = {
title = SV:T("Transpose in Key"),
message = SV:T("Choose key and transpose interval."),
buttons = "OkCancel",
widgets = {
{
name = "key",
type = "ComboBox",
label = SV:T("Key"),
choices = {"C","C#/Db","D","D#/Eb","E","F","F#/Gb","G","G#/Ab","A","A#/Bb","B"},
default = 0
},
{
name = "minor",
type = "CheckBox",
text = "Minor",
default = false
},
{
name = "interval",
type = "ComboBox",
label = SV:T("Interval"),
choices = {"+2nd", "+3rd", "+4th", "+5th", "+6th", "+7th", "+8ve", "-2nd", "-3rd", "-4th", "-5th", "-6th", "-7th", "-8ve"},
default = 3
},
}
}
return form
end
intervalToSemitones = {
{2,1},
{4,3},
{5,4,6},
{7,6,8},
{9,8,10},
{11,10},
{12},
{-2,-1},
{-4,-3},
{-5,-4,-6},
{-7,-6,-8},
{-9,-8,-10},
{-12},
}
keyNames = {"C","C#/Db","D","D#/Eb","E","F","F#/Gb","G","G#/Ab","A","A#/Bb","B"}
majorScale = {0,2,4,5,7,9,11,12}
minorScale = {0,2,3,5,7,8,10,12}
function isInKey(key, isMinor, note)
local noteWithoutOctave = note % 12
local keyRootNote = key - 1
local scale = nil
if isMinor then scale = minorScale else scale = majorScale end
for i = 1, #majorScale, 1 do
if (keyRootNote + scale[i]) % 12 == noteWithoutOctave then
return true
end
end
return false
end
function coreRoutine(formResult)
local notes = SV:getMainEditor():getSelection():getSelectedNotes()
--SV:showMessageBox("Transposing...", "notes: " .. #notes)
local key = formResult.answers.key + 1
local minor = formResult.answers.minor
local interval = formResult.answers.interval + 1
--SV:showMessageBox("Transposing...", "key: " .. key .. " minor: " .. minor .. " interval: " .. interval)
--SV:showMessageBox("Transposing...", "Key: " .. key .. " " .. keyNames[key] .. " minor: " .. minor .. " interval: " .. interval)
local intervalsToCheck = intervalToSemitones[interval]
--SV:showMessageBox("Transposing...", "Key: " .. keyNames[key] .. " interval: " .. interval .. " to check: " .. #intervalsToCheck)
for i = 1, #notes, 1 do
-- go through each note and increment it and snap it to the scale
local note = notes[i]:getPitch() - 60
--SV:showMessageBox("Transposing...", "note: " .. note)
for j = 1, #intervalsToCheck, 1 do
local tryNote = note + intervalsToCheck[j]
--SV:showMessageBox("Transposing...", "note: " .. note .. " + " .. intervalsToCheck[j] .. " -> " .. tryNote)
if isInKey(key, minor, tryNote) then
--SV:showMessageBox("Transposing...", "note: " .. note .. " -> " .. tryNote .. " is in key!")
notes[i]:setPitch(tryNote + 60)
break
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment