As a proof of concept that this was possible, I wrote a Dorico Lua script that generates 10 random major triads in root position.
This is nothing of value except to encourage folks to write scripts that do more than regurgitate Dorico commands. Please forgive my Lua expertise - it’s very rough and I’ve not played with it for many years.
I’ve not taken significant time to explore what’s possible, for I’m sure that a manual will come out some time soon. I wrote this after recording a script of inputting MIDI notes and chords and then looking at what code was generated.
Having said all of that, it would be fabulous if some sort of community library evolved that used appropriate namespace, objects, etc. so that we could share. My personal goal is from the point of view of an educator - I’d like to be able to generate, for my students, random worksheets based upon constraints I set.
To play with this script:
- Copy the code and pop it into a xxx.lua file located somewhere you can find it.
- In your Dorico score, Go into write mode, note input mode, put the cursor where you want it, and set the note value to what you want it to be.
- Do Script->Run Script… and choose your script.
- Edit it at will, and use the console to debug your changes
Cheers!
Henry
--[[
Requirements:
- Be in Write Mode
- Be in Note Entry mode
- Have the position where you want the notes entered
- Have the note value already chosen
Run the macro to get 10 major triads in root position. I have no control over how Dorico will spell them.
Notes:
This is a simple little test of Dorico for algorithmic generation.
My personal interest is in creating worksheets for students.
The goal of this test was to verify that this was a fully functionling Lua that I could
use to generate notes and to get enough of it working that I might start to think of ways to create worksheets
for students.
Warning - this is not well crafted code! Just a quick proof of concept. With that caveat, feel free to
use any part of this freely.
--]]
local app=DoApp.DoApp()
-- Info for the console.
local info = debug.getinfo(1,'S')
print("Running script: " .. info.source)
print("Dorico Lua Version: " .. _VERSION)
MIDI_NOTE_MIN = 0
MIDI_NOTE_MAX = 127
-- Seed the random number and run through a couple of times to avoid first or more repeated numbers
-- Don't know if needed...
-- see https://stackoverflow.com/questions/20154991/generating-uniform-random-numbers-in-lua
math.randomseed(os.time())
math.random(); math.random(); math.random()
-- For debugging
function print_r(arr, indentLevel)
local str = ""
local indentStr = "#"
if(indentLevel == nil) then
print(print_r(arr, 0))
return
end
for i = 0, indentLevel do
indentStr = indentStr.."\t"
end
for index,value in pairs(arr) do
if type(value) == "table" then
str = str..indentStr..index..": \n"..print_r(value, (indentLevel + 1))
else
str = str..indentStr..index..": "..value.."\n"
end
end
return str
end
-- Does "MIDI Input" of a chord, assuming Dorico is in Note Input mode and has a given duration
-- No input checking at the moment.
-- Returns nothing.
function noteInputChord(array)
pitches = ""
for index, value in next, array do
if (index > 1) then pitches = pitches .. "\\," end
pitches = pitches .. value
end
app:doCommand("NoteInput.MIDINoteInput?MIDIPitches=" .. pitches)
end
-- Pass in a root (MIDI number). Will limit the root to usable values if needed
-- Returns array of major triad (MIDI notes) in root position
function majorChord(root)
root = limitRange( root, MIDI_NOTE_MIN, MIDI_NOTE_MAX - 7)
return { root, root+4, root+7 }
end
-- Limits the range of a number to two
function limitRange(num, min, max)
if num < min then num = min elseif num > max then num = max end
return num
end
-- Limits the range of a MIID NOTE to a valid number
function limitNoteRange(num)
-- limit to integer
num = math.floor(num)
-- limit to valid range
return limitRange(num, MIDI_NOTE_MIN, MIDI_NOTE_MAX)
end
-- Accepts array with min/max keys.
-- Returns array of major triad (MIDI notes) in root position, root being passed in as MIDI number
function randomMajorChord(arr)
local function _randomMajorChord(min, max)
-- Flip min/max if in wrong order
if (min > max) then
min, max = max, min
print ("Warning: min/max flipped in randomMajorChord() call")
end
-- print("Random: " .. min .. ", " .. max .. "\n")
return majorChord( math.random(min, max) )
end
-- Verify the arguments and correct if needed
if type(arr) ~= "table" then
arr = { min = 60, max = 71 }
else
if type(arr.min) ~= "number" then arr.min = 60 else arr.min = limitNoteRange(arr.min) end
if type(arr.max) ~= "number" then arr.max = 71 else arr.max = limitNoteRange(arr.max) end
end
-- print_r(arr)
return _randomMajorChord( arr.min or 60, arr.max or 71 )
end
-- noteInputChord({48, 55, 52})
-- noteInputChord({60, 64, 67})
-- Change this loop
for i = 1, 10 do
-- Change this to set different min / max notes
-- 60 = middle C
noteInputChord(randomMajorChord({min = 60, max = 79}))
end
print("Success!\n")