Skip to content

Instantly share code, notes, and snippets.

@benjohnson2001
Created January 25, 2022 02:47
Show Gist options
  • Save benjohnson2001/01aa1df9c07779d087eaaedc51b52565 to your computer and use it in GitHub Desktop.
Save benjohnson2001/01aa1df9c07779d087eaaedc51b52565 to your computer and use it in GitHub Desktop.
-- @noindex
chords = {
{
name = 'major',
code = 'major',
display = '',
pattern = '10001001'
},
{
name = 'minor',
code = 'minor',
display = 'm',
pattern = '10010001'
},
{
name = 'power chord',
code = 'power',
display = '5',
pattern = '10000001'
},
{
name = 'suspended second',
code = 'sus2',
display = 'sus2',
pattern = '10100001'
},
{
name = 'suspended fourth',
code = 'sus4',
display = 'sus4',
pattern = '10000101'
},
{
name = 'diminished',
code = 'dim',
display = 'dim',
pattern = '1001001'
},
{
name = 'augmented',
code = 'aug',
display = 'aug',
pattern = '100010001'
},
{
name = 'major sixth',
code = 'maj6',
display = '6',
pattern = '1000100101'
},
{
name = 'minor sixth',
code = 'min6',
display = 'm6',
pattern = '1001000101'
},
{
name = 'dominant seventh',
code = '7',
display = '7',
pattern = '10001001001'
},
{
name = 'major seventh',
code = 'maj7',
display = 'maj7',
pattern = '100010010001'
},
{
name = 'minor seventh',
code = 'min7',
display = 'm7',
pattern = '10010001001'
},
{
name = 'flat fifth',
code = 'flat5',
display = '5-',
pattern = '10000010'
},
}
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
defaultScaleTonicNoteValue = 1
defaultScaleTypeValue = 1
defaultScaleNotesTextValue = ""
defaultChordTextValue = ""
defaultSelectedScaleNote = 1
defaultOctave = 3
defaultSelectedChordTypes = {}
for i = 1, 7 do
table.insert(defaultSelectedChordTypes, 1)
end
defaultInversionStates = {}
for i = 1, 7 do
table.insert(defaultInversionStates, 0)
end
defaultScaleNoteNames = {'C', 'D', 'E', 'F', 'G', 'A', 'B'}
defaultScaleDegreeHeaders = {'I', 'ii', 'iii', 'IV', 'V', 'vi', 'viio'}
defaultNotesThatArePlaying = {}
defaultDockState = 0x0201
defaultWindowShouldBeDocked = tostring(false)
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
local activeProjectIndex = 0
local sectionName = "com.pandabot.ChordGun"
local scaleTonicNoteKey = "scaleTonicNote"
local scaleTypeKey = "scaleType"
local scaleNotesTextKey = "scaleNotesText"
local chordTextKey = "chordText"
local chordInversionStatesKey = "chordInversionStates"
local selectedScaleNoteKey = "selectedScaleNote"
local octaveKey = "octave"
local selectedChordTypesKey = "selectedChordTypes"
local scaleNoteNamesKey = "scaleNoteNames"
local scaleDegreeHeadersKey = "scaleDegreeHeaders"
local notesThatArePlayingKey = "notesThatArePlaying"
local dockStateKey = "dockState"
local windowShouldBeDockedKey = "shouldBeDocked"
--
local function setValue(key, value)
reaper.SetProjExtState(activeProjectIndex, sectionName, key, value)
end
local function getValue(key, defaultValue)
local valueExists, value = reaper.GetProjExtState(activeProjectIndex, sectionName, key)
if valueExists == 0 then
setValue(key, defaultValue)
return defaultValue
end
return value
end
--
local function getTableFromString(arg)
local output = {}
for match in arg:gmatch("([^,%s]+)") do
output[#output + 1] = match
end
return output
end
local function setTableValue(key, value)
reaper.SetProjExtState(activeProjectIndex, sectionName, key, table.concat(value, ","))
end
local function getTableValue(key, defaultValue)
local valueExists, value = reaper.GetProjExtState(activeProjectIndex, sectionName, key)
if valueExists == 0 then
setTableValue(key, defaultValue)
return defaultValue
end
return getTableFromString(value)
end
--[[ ]]--
function getScaleTonicNote()
return tonumber(getValue(scaleTonicNoteKey, defaultScaleTonicNoteValue))
end
function setScaleTonicNote(arg)
setValue(scaleTonicNoteKey, arg)
end
--
function getScaleType()
return tonumber(getValue(scaleTypeKey, defaultScaleTypeValue))
end
function setScaleType(arg)
setValue(scaleTypeKey, arg)
end
--
function getScaleNotesText()
return getValue(scaleNotesTextKey, defaultScaleNotesTextValue)
end
function setScaleNotesText(arg)
setValue(scaleNotesTextKey, arg)
end
--
function getChordText()
return getValue(chordTextKey, defaultChordTextValue)
end
function setChordText(arg)
setValue(chordTextKey, arg)
end
--
function getChordInversionMin()
return -8
end
--
function getChordInversionMax()
return 8
end
--
function getSelectedScaleNote()
return tonumber(getValue(selectedScaleNoteKey, defaultSelectedScaleNote))
end
function setSelectedScaleNote(arg)
setValue(selectedScaleNoteKey, arg)
end
--
function getOctave()
return tonumber(getValue(octaveKey, defaultOctave))
end
function setOctave(arg)
setValue(octaveKey, arg)
end
--
function getOctaveMin()
return -1
end
--
function getOctaveMax()
return 8
end
--
function getSelectedChordTypes()
return getTableValue(selectedChordTypesKey, defaultSelectedChordTypes)
end
function getSelectedChordType(index)
local temp = getTableValue(selectedChordTypesKey, defaultSelectedChordTypes)
return tonumber(temp[index])
end
function setSelectedChordType(index, arg)
local temp = getSelectedChordTypes()
temp[index] = arg
setTableValue(selectedChordTypesKey, temp)
end
--
function getScaleNoteNames()
return getTableValue(scaleNoteNamesKey, defaultScaleNoteNames)
end
function getScaleNoteName(index)
local temp = getTableValue(scaleNoteNamesKey, defaultScaleNoteNames)
return temp[index]
end
function setScaleNoteName(index, arg)
local temp = getScaleNoteNames()
temp[index] = arg
setTableValue(scaleNoteNamesKey, temp)
end
--
function getScaleDegreeHeaders()
return getTableValue(scaleDegreeHeadersKey, defaultScaleDegreeHeaders)
end
function getScaleDegreeHeader(index)
local temp = getTableValue(scaleDegreeHeadersKey, defaultScaleDegreeHeaders)
return temp[index]
end
function setScaleDegreeHeader(index, arg)
local temp = getScaleDegreeHeaders()
temp[index] = arg
setTableValue(scaleDegreeHeadersKey, temp)
end
--
function getChordInversionStates()
return getTableValue(chordInversionStatesKey, defaultInversionStates)
end
function getChordInversionState(index)
local temp = getTableValue(chordInversionStatesKey, defaultInversionStates)
return tonumber(temp[index])
end
function setChordInversionState(index, arg)
local temp = getChordInversionStates()
temp[index] = arg
setTableValue(chordInversionStatesKey, temp)
end
--
function resetSelectedChordTypes()
local numberOfSelectedChordTypes = 7
for i = 1, numberOfSelectedChordTypes do
setSelectedChordType(i, 1)
end
end
function resetChordInversionStates()
local numberOfChordInversionStates = 7
for i = 1, numberOfChordInversionStates do
setChordInversionState(i, 0)
end
end
--
function getNotesThatArePlaying()
return getTableValue(notesThatArePlayingKey, defaultNotesThatArePlaying)
end
function setNotesThatArePlaying(arg)
setTableValue(notesThatArePlayingKey, arg)
end
--
function getDockState()
return getValue(dockStateKey, defaultDockState)
end
function setDockState(arg)
setValue(dockStateKey, arg)
end
function windowShouldBeDocked()
return getValue(windowShouldBeDockedKey, defaultWindowShouldBeDocked) == tostring(true)
end
function setWindowShouldBeDocked(arg)
setValue(windowShouldBeDockedKey, tostring(arg))
end
function mouseIsHoveringOver(element)
local x = gfx.mouse_x
local y = gfx.mouse_y
local isInHorizontalRegion = (x >= element.x and x < element.x+element.width)
local isInVerticalRegion = (y >= element.y and y < element.y+element.height)
return isInHorizontalRegion and isInVerticalRegion
end
function setPositionAtMouseCursor()
gfx.x = gfx.mouse_x
gfx.y = gfx.mouse_y
end
function leftMouseButtonIsHeldDown()
return gfx.mouse_cap & 1 == 1
end
function leftMouseButtonIsNotHeldDown()
return gfx.mouse_cap & 1 ~= 1
end
function rightMouseButtonIsHeldDown()
return gfx.mouse_cap & 2 == 2
end
function clearConsoleWindow()
reaper.ShowConsoleMsg("")
end
function print(arg)
reaper.ShowConsoleMsg(tostring(arg) .. "\n")
end
function getScreenWidth()
local _, _, screenWidth, _ = reaper.my_getViewport(0, 0, 0, 0, 0, 0, 0, 0, true)
return screenWidth
end
function getScreenHeight()
local _, _, _, screenHeight = reaper.my_getViewport(0, 0, 0, 0, 0, 0, 0, 0, true)
return screenHeight
end
function windowIsDocked()
return gfx.dock(-1) > 0
end
function windowIsNotDocked()
return not windowIsDocked()
end
function notesAreSelected()
local activeMidiEditor = reaper.MIDIEditor_GetActive()
local activeTake = reaper.MIDIEditor_GetTake(activeMidiEditor)
local noteIndex = 0
local noteExists = true
local noteIsSelected = false
while noteExists do
noteExists, noteIsSelected = reaper.MIDI_GetNote(activeTake, noteIndex)
if noteIsSelected then
return true
end
noteIndex = noteIndex + 1
end
return false
end
function startUndoBlock()
reaper.Undo_BeginBlock()
end
function endUndoBlock(actionDescription)
reaper.Undo_OnStateChange(actionDescription)
reaper.Undo_EndBlock(actionDescription, -1)
end
function emptyFunctionToPreventAutomaticCreationOfUndoPoint()
end
Timer = {}
Timer.__index = Timer
function Timer:new(numberOfSeconds)
local self = {}
setmetatable(self, Timer)
self.startingTime = reaper.time_precise()
self.numberOfSeconds = numberOfSeconds
self.timerIsStopped = true
return self
end
function Timer:start()
self.timerIsStopped = false
self.startingTime = reaper.time_precise()
end
function Timer:stop()
self.timerIsStopped = true
end
function Timer:timeHasElapsed()
local currentTime = reaper.time_precise()
if self.timerIsStopped then
return false
end
if currentTime - self.startingTime > self.numberOfSeconds then
return true
else
return false
end
end
function Timer:timeHasNotElapsed()
return not self:timeHasElapsed()
end
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
mouseButtonIsNotPressedDown = true
currentWidth = 0
scaleTonicNote = getScaleTonicNote()
scaleType = getScaleType()
guiShouldBeUpdated = false
scales = {
{ name = "Major", pattern = "101011010101" },
{ name = "Natural Minor", pattern = "101101011010" },
{ name = "Harmonic Minor", pattern = "101101011001" },
{ name = "Melodic Minor", pattern = "101101010101" },
{ name = "Pentatonic", pattern = "101010010100" },
{ name = "Ionian", pattern = "101011010101" },
{ name = "Aeolian", pattern = "101101011010" },
{ name = "Dorian", pattern = "101101010110" },
{ name = "Mixolydian", pattern = "101011010110" },
{ name = "Phrygian", pattern = "110101011010" },
{ name = "Lydian", pattern = "101010110101" },
{ name = "Locrian", pattern = "110101101010" }
}
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
notes = { 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B' };
flatNotes = { 'C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B' };
function getScalePattern(scaleTonicNote, scale)
local scalePatternString = scale['pattern']
local scalePattern = {false,false,false,false,false,false,false,false,false,false,false}
for i = 0, #scalePatternString do
local note = getNotesIndex(scaleTonicNote+i)
if scalePatternString:sub(i+1, i+1) == '1' then
scalePattern[note] = true
end
end
return scalePattern
end
function getNotesIndex(note)
return ((note - 1) % 12) + 1
end
function getNoteName(note)
local noteName = getSharpNoteName(note)
if not string.match(getScaleNotesText(), noteName) then
return getFlatNoteName(note)
else
return noteName
end
end
function getSharpNoteName(note)
local notesIndex = getNotesIndex(note)
return notes[notesIndex]
end
function getFlatNoteName(note)
local notesIndex = getNotesIndex(note)
return flatNotes[notesIndex]
end
function chordIsNotAlreadyIncluded(scaleChordsForRootNote, chordCode)
for chordIndex, chord in ipairs(scaleChordsForRootNote) do
if chord.code == chordCode then
return false
end
end
return true
end
function getNumberOfScaleChordsForScaleNoteIndex(scaleNoteIndex)
local chordCount = 0
local scaleChordsForRootNote = {}
for chordIndex, chord in ipairs(chords) do
if chordIsInScale(scaleNotes[scaleNoteIndex], chordIndex) then
chordCount = chordCount + 1
scaleChordsForRootNote[chordCount] = chord
end
end
return chordCount
end
function getScaleChordsForRootNote(rootNote)
local chordCount = 0
local scaleChordsForRootNote = {}
for chordIndex, chord in ipairs(chords) do
if chordIsInScale(rootNote, chordIndex) then
chordCount = chordCount + 1
scaleChordsForRootNote[chordCount] = chord
end
end
--[[
if preferences.enableModalMixtureCheckbox.value then
for chordIndex, chord in ipairs(chords) do
if chordIsNotAlreadyIncluded(scaleChordsForRootNote, chord.code) and chordIsInModalMixtureScale(rootNote, chordIndex) then
chordCount = chordCount + 1
scaleChordsForRootNote[chordCount] = chord
end
end
end
]]--
-- here is where you color the chord buttons differently
for chordIndex, chord in ipairs(chords) do
if chordIsNotAlreadyIncluded(scaleChordsForRootNote, chord.code) then
chordCount = chordCount + 1
scaleChordsForRootNote[chordCount] = chord
end
end
return scaleChordsForRootNote
end
function noteIsInScale(note)
return scalePattern[getNotesIndex(note)]
end
function noteIsNotInScale(note)
return not noteIsInScale(note)
end
function chordIsInScale(rootNote, chordIndex)
local chord = chords[chordIndex]
local chordPattern = chord['pattern']
for i = 0, #chordPattern do
local note = getNotesIndex(rootNote+i)
if chordPattern:sub(i+1, i+1) == '1' and noteIsNotInScale(note) then
return false
end
end
return true
end
function noteIsInModalMixtureScale(note)
local modalMixtureScaleType = 2
local modalMixtureScalePattern = getScalePattern(getScaleTonicNote(), scales[modalMixtureScaleType])
return modalMixtureScalePattern[getNotesIndex(note)]
end
function noteIsNotInModalMixtureScale(note)
return not noteIsInModalMixtureScale(note)
end
function chordIsInModalMixtureScale(rootNote, chordIndex)
local chord = chords[chordIndex]
local chordPattern = chord['pattern']
for i = 0, #chordPattern do
local note = getNotesIndex(rootNote+i)
if chordPattern:sub(i+1, i+1) == '1' and noteIsNotInModalMixtureScale(note) then
return false
end
end
return true
end
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
function updateScaleDegreeHeaders()
local minorSymbols = {'i', 'ii', 'iii', 'iv', 'v', 'vi', 'vii'}
local majorSymbols = {'I', 'II', 'III', 'IV', 'V', 'VI', 'VII'}
local diminishedSymbol = 'o'
local augmentedSymbol = '+'
local sixthSymbol = '6'
local seventhSymbol = '7'
local i = 1
for i = 1, #scaleNotes do
local symbol = ""
local chord = scaleChords[i][1]
if string.match(chord.code, "major") or chord.code == '7' then
symbol = majorSymbols[i]
else
symbol = minorSymbols[i]
end
if (chord.code == 'aug') then
symbol = symbol .. augmentedSymbol
end
if (chord.code == 'dim') then
symbol = symbol .. diminishedSymbol
end
if string.match(chord.code, "6") then
symbol = symbol .. sixthSymbol
end
if string.match(chord.code, "7") then
symbol = symbol .. seventhSymbol
end
setScaleDegreeHeader(i, symbol)
end
end
--[[
setDrawColorToRed()
gfx.setfont(1, "Arial") <-- default bitmap font does not support Unicode characters
local degreeSymbolCharacter = 0x00B0 <-- this is the degree symbol for augmented chords, "°"
gfx.drawchar(degreeSymbolCharacter)
]]--
local tolerance = 0.000001
function activeMidiEditor()
return reaper.MIDIEditor_GetActive()
end
function activeTake()
return reaper.MIDIEditor_GetTake(activeMidiEditor())
end
function activeMediaItem()
return reaper.GetMediaItemTake_Item(activeTake())
end
function activeTrack()
return reaper.GetMediaItemTake_Track(activeTake())
end
function mediaItemStartPosition()
return reaper.GetMediaItemInfo_Value(activeMediaItem(), "D_POSITION")
end
function mediaItemStartPositionPPQ()
return reaper.MIDI_GetPPQPosFromProjTime(activeTake(), mediaItemStartPosition())
end
function mediaItemStartPositionQN()
return reaper.MIDI_GetProjQNFromPPQPos(activeTake(), mediaItemStartPositionPPQ())
end
local function mediaItemLength()
return reaper.GetMediaItemInfo_Value(activeMediaItem(), "D_LENGTH")
end
local function mediaItemEndPosition()
return mediaItemStartPosition() + mediaItemLength()
end
local function cursorPosition()
return reaper.GetCursorPosition()
end
local function loopStartPosition()
local loopStartPosition, _ = reaper.GetSet_LoopTimeRange2(0, false, false, 0, 0, false)
return loopStartPosition
end
local function loopEndPosition()
local _, loopEndPosition = reaper.GetSet_LoopTimeRange2(0, false, false, 0, 0, false)
return loopEndPosition
end
local function noteLengthOld()
local noteLengthQN = getNoteLengthQN()
local noteLengthPPQ = reaper.MIDI_GetPPQPosFromProjQN(activeTake(), noteLengthQN)
return reaper.MIDI_GetProjTimeFromPPQPos(activeTake(), noteLengthPPQ)
end
local function noteLength()
return gridUnitLength()
end
function notCurrentlyRecording()
local activeProjectIndex = 0
return reaper.GetPlayStateEx(activeProjectIndex) & 4 ~= 4
end
function setEditCursorPosition(arg)
local activeProjectIndex = 0
local moveView = false
local seekPlay = false
reaper.SetEditCurPos2(activeProjectIndex, arg, moveView, seekPlay)
end
local function moveEditCursorPosition(arg)
local moveTimeSelection = false
reaper.MoveEditCursor(arg, moveTimeSelection)
end
local function repeatIsNotOn()
return reaper.GetSetRepeat(-1) == 0
end
local function loopIsActive()
if repeatIsNotOn() then
return false
end
if loopStartPosition() < mediaItemStartPosition() and loopEndPosition() < mediaItemStartPosition() then
return false
end
if loopStartPosition() > mediaItemEndPosition() and loopEndPosition() > mediaItemEndPosition() then
return false
end
if loopStartPosition() == loopEndPosition() then
return false
else
return true
end
end
function moveCursor(keepNotesSelected, noteEndPosition)
if keepNotesSelected then
local noteEndPositionInProjTime = reaper.MIDI_GetProjTimeFromPPQPos(activeTake(), noteEndPosition)
local noteLengthOfSelectedNote = noteEndPositionInProjTime-cursorPosition()
if loopIsActive() and loopEndPosition() < mediaItemEndPosition() then
if cursorPosition() + noteLengthOfSelectedNote >= loopEndPosition() - tolerance then
if loopStartPosition() > mediaItemStartPosition() then
setEditCursorPosition(loopStartPosition())
else
setEditCursorPosition(mediaItemStartPosition())
end
else
moveEditCursorPosition(noteLengthOfSelectedNote)
end
elseif loopIsActive() and mediaItemEndPosition() <= loopEndPosition() then
if cursorPosition() + noteLengthOfSelectedNote >= mediaItemEndPosition() - tolerance then
if loopStartPosition() > mediaItemStartPosition() then
setEditCursorPosition(loopStartPosition())
else
setEditCursorPosition(mediaItemStartPosition())
end
else
moveEditCursorPosition(noteLengthOfSelectedNote)
end
elseif cursorPosition() + noteLengthOfSelectedNote >= mediaItemEndPosition() - tolerance then
setEditCursorPosition(mediaItemStartPosition())
else
moveEditCursorPosition(noteLengthOfSelectedNote)
end
else
if loopIsActive() and loopEndPosition() < mediaItemEndPosition() then
if cursorPosition() + noteLength() >= loopEndPosition() - tolerance then
if loopStartPosition() > mediaItemStartPosition() then
setEditCursorPosition(loopStartPosition())
else
setEditCursorPosition(mediaItemStartPosition())
end
else
moveEditCursorPosition(noteLength())
end
elseif loopIsActive() and mediaItemEndPosition() <= loopEndPosition() then
if cursorPosition() + noteLength() >= mediaItemEndPosition() - tolerance then
if loopStartPosition() > mediaItemStartPosition() then
setEditCursorPosition(loopStartPosition())
else
setEditCursorPosition(mediaItemStartPosition())
end
else
moveEditCursorPosition(noteLength())
end
elseif cursorPosition() + noteLength() >= mediaItemEndPosition() - tolerance then
setEditCursorPosition(mediaItemStartPosition())
else
moveEditCursorPosition(noteLength())
end
end
end
--
function getCursorPositionPPQ()
return reaper.MIDI_GetPPQPosFromProjTime(activeTake(), cursorPosition())
end
local function getCursorPositionQN()
return reaper.MIDI_GetProjQNFromPPQPos(activeTake(), getCursorPositionPPQ())
end
function getNoteLengthQN()
local gridLength = reaper.MIDI_GetGrid(activeTake())
return gridLength
end
function gridUnitLength()
local gridLengthQN = reaper.MIDI_GetGrid(activeTake())
local mediaItemPlusGridLengthPPQ = reaper.MIDI_GetPPQPosFromProjQN(activeTake(), mediaItemStartPositionQN() + gridLengthQN)
local mediaItemPlusGridLength = reaper.MIDI_GetProjTimeFromPPQPos(activeTake(), mediaItemPlusGridLengthPPQ)
return mediaItemPlusGridLength - mediaItemStartPosition()
end
function getMidiEndPositionPPQ()
local startPosition = reaper.GetCursorPosition()
local startPositionPPQ = reaper.MIDI_GetPPQPosFromProjTime(activeTake(), startPosition)
local endPositionPPQ = reaper.MIDI_GetPPQPosFromProjTime(activeTake(), startPosition+gridUnitLength())
return endPositionPPQ
end
function deselectAllNotes()
local selectAllNotes = false
reaper.MIDI_SelectAll(activeTake(), selectAllNotes)
end
function getCurrentNoteChannel(channelArg)
if channelArg ~= nil then
return channelArg
end
if activeMidiEditor() == nil then
return 0
end
return reaper.MIDIEditor_GetSetting_int(activeMidiEditor(), "default_note_chan")
end
function getCurrentVelocity()
if activeMidiEditor() == nil then
return 96
end
return reaper.MIDIEditor_GetSetting_int(activeMidiEditor(), "default_note_vel")
end
function getNumberOfNotes()
local _, numberOfNotes = reaper.MIDI_CountEvts(activeTake())
return numberOfNotes
end
function deleteNote(noteIndex)
reaper.MIDI_DeleteNote(activeTake(), noteIndex)
end
function thereAreNotesSelected()
if activeTake() == nil then
return false
end
local numberOfNotes = getNumberOfNotes()
for noteIndex = 0, numberOfNotes-1 do
local _, noteIsSelected = reaper.MIDI_GetNote(activeTake(), noteIndex)
if noteIsSelected then
return true
end
end
return false
end
function halveGridSize()
if activeTake() == nil then
return
end
local gridSize = reaper.MIDI_GetGrid(activeTake())/4
if gridSize <= 1/1024 then
return
end
local activeProjectIndex = 0
reaper.SetMIDIEditorGrid(activeProjectIndex, gridSize/2)
end
function doubleGridSize()
if activeTake() == nil then
return
end
local gridSize = reaper.MIDI_GetGrid(activeTake())/4
if gridSize >= 1024 then
return
end
local activeProjectIndex = 0
reaper.SetMIDIEditorGrid(activeProjectIndex, gridSize*2)
end
--
function deleteExistingNotesInNextInsertionTimePeriod(keepNotesSelected, noteEndPosition)
local insertionStartTime = cursorPosition()
local insertionEndTime = nil
if keepNotesSelected then
insertionEndTime = reaper.MIDI_GetProjTimeFromPPQPos(activeTake(), noteEndPosition)
else
insertionEndTime = insertionStartTime + noteLength()
end
local numberOfNotes = getNumberOfNotes()
for noteIndex = numberOfNotes-1, 0, -1 do
local _, _, _, noteStartPositionPPQ = reaper.MIDI_GetNote(activeTake(), noteIndex)
local noteStartTime = reaper.MIDI_GetProjTimeFromPPQPos(activeTake(), noteStartPositionPPQ)
if noteStartTime + tolerance >= insertionStartTime and noteStartTime + tolerance <= insertionEndTime then
deleteNote(noteIndex)
end
end
end
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
function playMidiNote(midiNote)
local virtualKeyboardMode = 0
local channel = getCurrentNoteChannel()
local noteOnCommand = 0x90 + channel
local velocity = getCurrentVelocity()
reaper.StuffMIDIMessage(virtualKeyboardMode, noteOnCommand, midiNote, velocity)
end
function stopAllNotesFromPlaying()
for midiNote = 0, 127 do
local virtualKeyboardMode = 0
local channel = getCurrentNoteChannel()
local noteOffCommand = 0x80 + channel
local velocity = 0
reaper.StuffMIDIMessage(virtualKeyboardMode, noteOffCommand, midiNote, velocity)
end
end
function stopNoteFromPlaying(midiNote)
local virtualKeyboardMode = 0
local channel = getCurrentNoteChannel()
local noteOffCommand = 0x80 + channel
local velocity = 0
reaper.StuffMIDIMessage(virtualKeyboardMode, noteOffCommand, midiNote, velocity)
end
function stopNotesFromPlaying()
local notesThatArePlaying = getNotesThatArePlaying()
for noteIndex = 1, #notesThatArePlaying do
stopNoteFromPlaying(notesThatArePlaying[noteIndex])
end
setNotesThatArePlaying({})
end
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
function applyInversion(chord)
local chordLength = #chord
local selectedScaleNote = getSelectedScaleNote()
local chordInversionValue = getChordInversionState(selectedScaleNote)
local chord_ = chord
local oct = 0
if chordInversionValue < 0 then
oct = math.floor(chordInversionValue / chordLength)
chordInversionValue = chordInversionValue + (math.abs(oct) * chordLength)
end
for i = 1, chordInversionValue do
local r = table.remove(chord_, 1)
r = r + 12
table.insert(chord_, #chord_ + 1, r )
end
for i = 1, #chord_ do
chord_[i] = chord_[i] + (oct * 12)
end
return chord_
end
function getChordNotesArray(root, chord, octave)
local chordLength = 0
local chordNotesArray = {}
local chordPattern = chord["pattern"]
for n = 0, #chordPattern-1 do
if chordPattern:sub(n+1, n+1) == '1' then
chordLength = chordLength + 1
local noteValue = root + n + ((octave+1) * 12) - 1
table.insert(chordNotesArray, noteValue)
end
end
chordNotesArray = applyInversion(chordNotesArray)
return chordNotesArray
end
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
function insertMidiNote(note, keepNotesSelected, noteEndPosition)
local noteIsMuted = false
local startPosition = getCursorPositionPPQ()
local endPosition = nil
if keepNotesSelected then
endPosition = noteEndPosition
else
endPosition = getMidiEndPositionPPQ()
end
local channel = getCurrentNoteChannel()
local velocity = getCurrentVelocity()
local noSort = false
reaper.MIDI_InsertNote(activeTake(), keepNotesSelected, noteIsMuted, startPosition, endPosition, channel, note, velocity, noSort)
end
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
local function playScaleChord(chordNotesArray)
stopNotesFromPlaying()
for note = 1, #chordNotesArray do
playMidiNote(chordNotesArray[note])
end
setNotesThatArePlaying(chordNotesArray)
end
function previewScaleChord()
local scaleNoteIndex = getSelectedScaleNote()
local chordTypeIndex = getSelectedChordType(scaleNoteIndex)
local root = scaleNotes[scaleNoteIndex]
local chord = scaleChords[scaleNoteIndex][chordTypeIndex]
local octave = getOctave()
local chordNotesArray = getChordNotesArray(root, chord, octave)
playScaleChord(chordNotesArray)
updateChordText(root, chord, chordNotesArray)
end
function insertScaleChord(chordNotesArray, keepNotesSelected, noteEndPosition)
deleteExistingNotesInNextInsertionTimePeriod(keepNotesSelected, noteEndPosition)
for note = 1, #chordNotesArray do
insertMidiNote(chordNotesArray[note], keepNotesSelected, noteEndPosition)
end
moveCursor(keepNotesSelected, noteEndPosition)
end
function playOrInsertScaleChord(actionDescription)
local scaleNoteIndex = getSelectedScaleNote()
local chordTypeIndex = getSelectedChordType(scaleNoteIndex)
local root = scaleNotes[scaleNoteIndex]
local chord = scaleChords[scaleNoteIndex][chordTypeIndex]
local octave = getOctave()
local chordNotesArray = getChordNotesArray(root, chord, octave)
if activeTake() ~= nil and notCurrentlyRecording() then
startUndoBlock()
if thereAreNotesSelected() then
changeSelectedNotesToScaleChords(chordNotesArray)
else
insertScaleChord(chordNotesArray, false)
end
endUndoBlock(actionDescription)
end
playScaleChord(chordNotesArray)
updateChordText(root, chord, chordNotesArray)
end
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
local function playScaleNote(noteValue)
stopNotesFromPlaying()
playMidiNote(noteValue)
setNotesThatArePlaying({noteValue})
setChordText("")
end
function insertScaleNote(noteValue, keepNotesSelected, noteEndPosition)
deleteExistingNotesInNextInsertionTimePeriod(keepNotesSelected, noteEndPosition)
insertMidiNote(noteValue, keepNotesSelected, noteEndPosition)
moveCursor(keepNotesSelected, noteEndPosition)
end
function previewScaleNote(octaveAdjustment)
local scaleNoteIndex = getSelectedScaleNote()
local root = scaleNotes[scaleNoteIndex]
local octave = getOctave()
local noteValue = root + ((octave+1+octaveAdjustment) * 12) - 1
playScaleNote(noteValue)
end
function playOrInsertScaleNote(octaveAdjustment, actionDescription)
local scaleNoteIndex = getSelectedScaleNote()
local root = scaleNotes[scaleNoteIndex]
local octave = getOctave()
local noteValue = root + ((octave+1+octaveAdjustment) * 12) - 1
if activeTake() ~= nil and notCurrentlyRecording() then
startUndoBlock()
if thereAreNotesSelected() then
changeSelectedNotesToScaleNotes(noteValue)
else
insertScaleNote(noteValue, false)
end
endUndoBlock(actionDescription)
end
playScaleNote(noteValue)
end
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
local function getNoteStartingPositions()
local numberOfNotes = getNumberOfNotes()
local previousNoteStartPositionPPQ = -1
local noteStartingPositions = {}
for noteIndex = 0, numberOfNotes-1 do
local _, noteIsSelected, noteIsMuted, noteStartPositionPPQ, noteEndPositionPPQ = reaper.MIDI_GetNote(activeTake(), noteIndex)
if noteIsSelected then
if noteStartPositionPPQ ~= previousNoteStartPositionPPQ then
table.insert(noteStartingPositions, noteStartPositionPPQ)
end
previousNoteStartPositionPPQ = noteStartPositionPPQ
end
end
return noteStartingPositions
end
local function getNoteEndingPositions()
local numberOfNotes = getNumberOfNotes()
local previousNoteEndPositionPPQ = -1
local noteEndingPositions = {}
for noteIndex = 0, numberOfNotes-1 do
local _, noteIsSelected, noteIsMuted, noteStartPositionPPQ, noteEndPositionPPQ = reaper.MIDI_GetNote(activeTake(), noteIndex)
if noteIsSelected then
if noteEndPositionPPQ ~= previousNoteEndPositionPPQ then
table.insert(noteEndingPositions, noteEndPositionPPQ)
end
previousNoteEndPositionPPQ = noteEndPositionPPQ
end
end
return noteEndingPositions
end
local function deleteSelectedNotes()
local numberOfNotes = getNumberOfNotes()
for noteIndex = numberOfNotes-1, 0, -1 do
local _, noteIsSelected = reaper.MIDI_GetNote(activeTake(), noteIndex)
if noteIsSelected then
deleteNote(noteIndex)
end
end
end
local function setEditCursorTo(arg)
local cursorPosition = reaper.MIDI_GetProjTimeFromPPQPos(activeTake(), arg)
setEditCursorPosition(cursorPosition)
end
function changeSelectedNotesToScaleChords(chordNotesArray)
local noteStartingPositions = getNoteStartingPositions()
local noteEndingPositions = getNoteEndingPositions()
deleteSelectedNotes()
for i = 1, #noteStartingPositions do
setEditCursorTo(noteStartingPositions[i])
insertScaleChord(chordNotesArray, true, noteEndingPositions[i])
end
end
function changeSelectedNotesToScaleNotes(noteValue)
local noteStartingPositions = getNoteStartingPositions()
local noteEndingPositions = getNoteEndingPositions()
deleteSelectedNotes()
for i = 1, #noteStartingPositions do
setEditCursorTo(noteStartingPositions[i])
insertScaleNote(noteValue, true, noteEndingPositions[i])
end
end
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
scaleNotes = {}
scaleChords = {}
scalePattern = nil
chordButtons = {}
function getNotesString(chordNotesArray)
local notesString = ''
for i, note in ipairs(chordNotesArray) do
local noteName = getNoteName(note+1)
if i ~= #chordNotesArray then
notesString = notesString .. noteName .. ','
else
notesString = notesString .. noteName .. ''
end
end
return notesString
end
--------------------------------------------------------------------------------
function updateScaleNotes()
scaleNotes = {}
local scaleNoteIndex = 1
for note = getScaleTonicNote(), getScaleTonicNote() + 11 do
if noteIsInScale(note) then
scaleNotes[scaleNoteIndex] = note
scaleNoteIndex = scaleNoteIndex + 1
end
end
end
function updateScaleChords()
scaleChords = {}
local scaleNoteIndex = 1
for note = getScaleTonicNote(), getScaleTonicNote() + 11 do
if noteIsInScale(note) then
scaleChords[scaleNoteIndex] = getScaleChordsForRootNote(note)
scaleNoteIndex = scaleNoteIndex + 1
end
end
end
function removeFlatsAndSharps(arg)
return arg:gsub('b',''):gsub('#','')
end
function aNoteIsRepeated()
local numberOfScaleNoteNames = 7
local previousScaleNoteName = getScaleNoteName(numberOfScaleNoteNames)
local scaleNoteName = nil
for scaleDegree = 1, numberOfScaleNoteNames do
scaleNoteName = getScaleNoteName(scaleDegree)
if removeFlatsAndSharps(scaleNoteName) == removeFlatsAndSharps(previousScaleNoteName) then
return true
end
previousScaleNoteName = scaleNoteName
end
return false
end
function updateScaleNoteNames()
local previousScaleNoteName = getSharpNoteName(getScaleTonicNote() + 11)
local scaleNoteName = nil
local scaleDegree = 1
for note = getScaleTonicNote(), getScaleTonicNote() + 11 do
if scalePattern[getNotesIndex(note)] then
scaleNoteName = getSharpNoteName(note)
setScaleNoteName(scaleDegree, scaleNoteName)
scaleDegree = scaleDegree + 1
previousScaleNoteName = scaleNoteName
end
end
if aNoteIsRepeated() then
local previousScaleNoteName = getFlatNoteName(getScaleTonicNote() + 11)
local scaleNoteName = nil
local scaleDegree = 1
for note = getScaleTonicNote(), getScaleTonicNote() + 11 do
if scalePattern[getNotesIndex(note)] then
scaleNoteName = getFlatNoteName(note)
setScaleNoteName(scaleDegree, scaleNoteName)
scaleDegree = scaleDegree + 1
previousScaleNoteName = scaleNoteName
end
end
end
end
function updateScaleNotesText()
local scaleNotesText = ''
for i = 1, #scaleNotes do
if scaleNotesText ~= '' then
scaleNotesText = scaleNotesText .. ', '
end
scaleNotesText = scaleNotesText .. getScaleNoteName(i)
end
setScaleNotesText(scaleNotesText)
end
function getChordInversionText(chordNotesArray)
local selectedScaleNote = getSelectedScaleNote()
local inversionValue = getChordInversionState(selectedScaleNote)
if inversionValue == 0 then
return ''
end
if math.fmod(inversionValue, #chordNotesArray) == 0 then
return ''
end
return '/' .. getNoteName(chordNotesArray[1]+1)
end
function getChordInversionOctaveIndicator(numberOfChordNotes)
local selectedScaleNote = getSelectedScaleNote()
local inversionValue = getChordInversionState(selectedScaleNote)
local octaveIndicator = nil
if inversionValue > 0 then
local offsetValue = math.floor(inversionValue / numberOfChordNotes)
if offsetValue > 0 then
return '+' .. offsetValue
else
return '+'
end
elseif inversionValue < 0 then
local offsetValue = math.abs(math.ceil(inversionValue / numberOfChordNotes))
if offsetValue > 0 then
return '-' .. offsetValue
else
return '-'
end
else
return ''
end
end
function updateChordText(root, chord, chordNotesArray)
local rootNoteName = getNoteName(root)
local chordInversionText = getChordInversionText(chordNotesArray)
local chordInversionOctaveIndicator = getChordInversionOctaveIndicator(#chordNotesArray)
local chordString = rootNoteName .. chord["display"]
local notesString = getNotesString(chordNotesArray)
local chordTextValue = ''
if string.match(chordInversionOctaveIndicator, "-") then
chordTextValue = ("%s%12s%s%12s"):format(chordInversionOctaveIndicator, chordString, chordInversionText, notesString)
elseif string.match(chordInversionOctaveIndicator, "+") then
chordTextValue = ("%s%12s%s%12s%12s"):format('', chordString, chordInversionText, notesString, chordInversionOctaveIndicator)
else
chordTextValue = ("%s%12s%s%12s"):format('', chordString, chordInversionText, notesString)
end
setChordText(chordTextValue)
showChordText()
end
function showChordText()
local chordText = getChordText()
reaper.Help_Set(chordText, false)
end
function updateScaleData()
scalePattern = getScalePattern(getScaleTonicNote(), scales[getScaleType()])
updateScaleNotes()
updateScaleNoteNames()
updateScaleNotesText()
updateScaleChords()
updateScaleDegreeHeaders()
end
function showScaleStatus()
local scaleTonicText = notes[getScaleTonicNote()]
local scaleTypeText = scales[getScaleType()].name
local scaleNotesText = getScaleNotesText()
reaper.Help_Set(("%s %s: %s"):format(scaleTonicText, scaleTypeText, scaleNotesText), false)
end
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
local function transposeSelectedNotes(numberOfSemitones)
local numberOfNotes = getNumberOfNotes()
for noteIndex = numberOfNotes-1, 0, -1 do
local _, noteIsSelected, noteIsMuted, noteStartPositionPPQ, noteEndPositionPPQ, channel, pitch, velocity = reaper.MIDI_GetNote(activeTake(), noteIndex)
if noteIsSelected then
deleteNote(noteIndex)
local noSort = false
reaper.MIDI_InsertNote(activeTake(), noteIsSelected, noteIsMuted, noteStartPositionPPQ, noteEndPositionPPQ, channel, pitch+numberOfSemitones, velocity, noSort)
end
end
end
function transposeSelectedNotesUpOneOctave()
transposeSelectedNotes(12)
end
function transposeSelectedNotesDownOneOctave()
transposeSelectedNotes(-12)
end
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
local function decrementChordInversion()
local selectedScaleNote = getSelectedScaleNote()
local chordInversionMin = getChordInversionMin()
local chordInversion = getChordInversionState(selectedScaleNote)
if chordInversion <= chordInversionMin then
return
end
setChordInversionState(selectedScaleNote, chordInversion-1)
end
function decrementChordInversionAction()
local actionDescription = "decrement chord inversion"
decrementChordInversion()
playOrInsertScaleChord(actionDescription)
end
--
local function incrementChordInversion()
local selectedScaleNote = getSelectedScaleNote()
local chordInversionMax = getChordInversionMax()
local chordInversion = getChordInversionState(selectedScaleNote)
if chordInversion >= chordInversionMax then
return
end
setChordInversionState(selectedScaleNote, chordInversion+1)
end
function incrementChordInversionAction()
local actionDescription = "increment chord inversion"
incrementChordInversion()
playOrInsertScaleChord(actionDescription)
end
--
local function decrementChordType()
local selectedScaleNote = getSelectedScaleNote()
local selectedChordType = getSelectedChordType(selectedScaleNote)
if selectedChordType <= 1 then
return
end
setSelectedChordType(selectedScaleNote, selectedChordType-1)
end
function decrementChordTypeAction()
local actionDescription = "decrement chord type"
decrementChordType()
playOrInsertScaleChord(actionDescription)
end
--
local function incrementChordType()
local selectedScaleNote = getSelectedScaleNote()
local selectedChordType = getSelectedChordType(selectedScaleNote)
if selectedChordType >= #chords then
return
end
setSelectedChordType(selectedScaleNote, selectedChordType+1)
end
function incrementChordTypeAction()
local actionDescription = "increment chord type"
incrementChordType()
playOrInsertScaleChord(actionDescription)
end
--
function playTonicNote()
local root = scaleNotes[1]
local octave = getOctave()
local noteValue = root + ((octave+1) * 12) - 1
stopNotesFromPlaying()
playMidiNote(noteValue)
setNotesThatArePlaying({noteValue})
end
local function decrementOctave()
local octave = getOctave()
if octave <= getOctaveMin() then
return
end
setOctave(octave-1)
end
function decrementOctaveAction()
decrementOctave()
if thereAreNotesSelected() then
startUndoBlock()
transposeSelectedNotesDownOneOctave()
endUndoBlock("decrement octave")
else
playTonicNote()
end
end
--
local function incrementOctave()
local octave = getOctave()
if octave >= getOctaveMax() then
return
end
setOctave(octave+1)
end
function incrementOctaveAction()
incrementOctave()
if thereAreNotesSelected() then
startUndoBlock()
transposeSelectedNotesUpOneOctave()
endUndoBlock("increment octave")
else
playTonicNote()
end
end
--
local function decrementScaleTonicNote()
local scaleTonicNote = getScaleTonicNote()
if scaleTonicNote <= 1 then
return
end
setScaleTonicNote(scaleTonicNote-1)
end
function decrementScaleTonicNoteAction()
decrementScaleTonicNote()
setSelectedScaleNote(1)
setChordText("")
resetSelectedChordTypes()
resetChordInversionStates()
updateScaleData()
updateScaleDegreeHeaders()
showScaleStatus()
end
--
local function incrementScaleTonicNote()
local scaleTonicNote = getScaleTonicNote()
if scaleTonicNote >= #notes then
return
end
setScaleTonicNote(scaleTonicNote+1)
end
function incrementScaleTonicNoteAction()
incrementScaleTonicNote()
setSelectedScaleNote(1)
setChordText("")
resetSelectedChordTypes()
resetChordInversionStates()
updateScaleData()
updateScaleDegreeHeaders()
showScaleStatus()
end
--
local function decrementScaleType()
local scaleType = getScaleType()
if scaleType <= 1 then
return
end
setScaleType(scaleType-1)
end
function decrementScaleTypeAction()
decrementScaleType()
setSelectedScaleNote(1)
setChordText("")
resetSelectedChordTypes()
resetChordInversionStates()
updateScaleData()
updateScaleDegreeHeaders()
showScaleStatus()
end
--
local function incrementScaleType()
local scaleType = getScaleType()
if scaleType >= #scales then
return
end
setScaleType(scaleType+1)
end
function incrementScaleTypeAction()
incrementScaleType()
setSelectedScaleNote(1)
setChordText("")
resetSelectedChordTypes()
resetChordInversionStates()
updateScaleData()
updateScaleDegreeHeaders()
showScaleStatus()
end
----
local function scaleIsPentatonic()
local scaleType = getScaleType()
local scaleTypeName = string.lower(scales[scaleType].name)
return string.match(scaleTypeName, "pentatonic")
end
function scaleChordAction(scaleNoteIndex)
if scaleIsPentatonic() and scaleNoteIndex > 5 then
return
end
setSelectedScaleNote(scaleNoteIndex)
local selectedChordType = getSelectedChordType(scaleNoteIndex)
local chord = scaleChords[scaleNoteIndex][selectedChordType]
local actionDescription = "scale chord " .. scaleNoteIndex .. " (" .. chord.code .. ")"
playOrInsertScaleChord(actionDescription)
end
function previewScaleChordAction(scaleNoteIndex)
if scaleIsPentatonic() and scaleNoteIndex > 5 then
return
end
setSelectedScaleNote(scaleNoteIndex)
previewScaleChord()
end
--
function scaleNoteAction(scaleNoteIndex)
if scaleIsPentatonic() and scaleNoteIndex > 5 then
return
end
setSelectedScaleNote(scaleNoteIndex)
local actionDescription = "scale note " .. scaleNoteIndex
playOrInsertScaleNote(0, actionDescription)
end
--
function lowerScaleNoteAction(scaleNoteIndex)
if scaleIsPentatonic() and scaleNoteIndex > 5 then
return
end
if getOctave() <= getOctaveMin() then
return
end
setSelectedScaleNote(scaleNoteIndex)
local actionDescription = "lower scale note " .. scaleNoteIndex
playOrInsertScaleNote(-1, actionDescription)
end
--
function higherScaleNoteAction(scaleNoteIndex)
if scaleIsPentatonic() and scaleNoteIndex > 5 then
return
end
if getOctave() >= getOctaveMax() then
return
end
setSelectedScaleNote(scaleNoteIndex)
local actionDescription = "higher scale note " .. scaleNoteIndex
playOrInsertScaleNote(1, actionDescription)
end
--
function previewScaleNoteAction(scaleNoteIndex)
if scaleIsPentatonic() and scaleNoteIndex > 5 then
return
end
setSelectedScaleNote(scaleNoteIndex)
previewScaleNote(0)
end
function previewLowerScaleNoteAction(scaleNoteIndex)
if scaleIsPentatonic() and scaleNoteIndex > 5 then
return
end
if getOctave() <= getOctaveMin() then
return
end
setSelectedScaleNote(scaleNoteIndex)
previewScaleNote(-1)
end
function previewHigherScaleNoteAction(scaleNoteIndex)
if scaleIsPentatonic() and scaleNoteIndex > 5 then
return
end
if getOctave() >= getOctaveMax() then
return
end
setSelectedScaleNote(scaleNoteIndex)
previewScaleNote(1)
end
function drawDropdownIcon()
local xOffset = gfx.x
local yOffset = gfx.y
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 1 + xOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.y = 1 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = xOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 1 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.38823529411765)
gfx.x = xOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 1 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = xOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 1 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = xOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 1 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.36078431372549, 0.39607843137255, 0.3843137254902)
gfx.x = xOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 1 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = xOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 1 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = xOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 1 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = xOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 1 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = xOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 1 + xOffset
gfx.y = 10 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = xOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 1 + xOffset
gfx.y = 11 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = xOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 1 + xOffset
gfx.y = 12 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = xOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 1 + xOffset
gfx.y = 13 + yOffset
gfx.setpixel(0.34901960784314, 0.37647058823529, 0.36470588235294)
gfx.x = xOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 1 + xOffset
gfx.y = 14 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 2 + xOffset
gfx.y = yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.y = 1 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 2 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 2 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 2 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 2 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.3843137254902, 0.4156862745098, 0.40392156862745)
gfx.x = 2 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 2 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 2 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 2 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 2 + xOffset
gfx.y = 10 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 2 + xOffset
gfx.y = 11 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 2 + xOffset
gfx.y = 12 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 2 + xOffset
gfx.y = 13 + yOffset
gfx.setpixel(0.34901960784314, 0.37647058823529, 0.36470588235294)
gfx.x = 2 + xOffset
gfx.y = 14 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 3 + xOffset
gfx.y = yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.y = 1 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 3 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 3 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.35294117647059, 0.3843137254902, 0.37254901960784)
gfx.x = 3 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.41176470588235, 0.43921568627451, 0.42745098039216)
gfx.x = 3 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.67843137254902, 0.69411764705882, 0.69019607843137)
gfx.x = 3 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.50196078431373, 0.52549019607843, 0.51764705882353)
gfx.x = 3 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.36078431372549, 0.39607843137255, 0.38039215686275)
gfx.x = 3 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 3 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 3 + xOffset
gfx.y = 10 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 3 + xOffset
gfx.y = 11 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 3 + xOffset
gfx.y = 12 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 3 + xOffset
gfx.y = 13 + yOffset
gfx.setpixel(0.34901960784314, 0.37647058823529, 0.36470588235294)
gfx.x = 3 + xOffset
gfx.y = 14 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 4 + xOffset
gfx.y = yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.y = 1 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 4 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 4 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.34509803921569, 0.37647058823529, 0.36470588235294)
gfx.x = 4 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.43529411764706, 0.46274509803922, 0.45098039215686)
gfx.x = 4 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.92156862745098, 0.92549019607843, 0.92549019607843)
gfx.x = 4 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.85882352941176, 0.86274509803922, 0.86274509803922)
gfx.x = 4 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.53725490196078, 0.56078431372549, 0.55294117647059)
gfx.x = 4 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.36470588235294, 0.4, 0.38823529411765)
gfx.x = 4 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.36078431372549, 0.3921568627451, 0.38039215686275)
gfx.x = 4 + xOffset
gfx.y = 10 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 4 + xOffset
gfx.y = 11 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 4 + xOffset
gfx.y = 12 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 4 + xOffset
gfx.y = 13 + yOffset
gfx.setpixel(0.34901960784314, 0.37647058823529, 0.36470588235294)
gfx.x = 4 + xOffset
gfx.y = 14 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 5 + xOffset
gfx.y = yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.y = 1 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 5 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 5 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.34509803921569, 0.38039215686275, 0.36470588235294)
gfx.x = 5 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.43529411764706, 0.46274509803922, 0.45098039215686)
gfx.x = 5 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.94901960784314, 0.95294117647059, 0.95294117647059)
gfx.x = 5 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(1.0, 1.0, 1.0)
gfx.x = 5 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.90196078431373, 0.90588235294118, 0.90196078431373)
gfx.x = 5 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.6, 0.6156862745098, 0.61176470588235)
gfx.x = 5 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.3921568627451, 0.42352941176471, 0.41176470588235)
gfx.x = 5 + xOffset
gfx.y = 10 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 5 + xOffset
gfx.y = 11 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 5 + xOffset
gfx.y = 12 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 5 + xOffset
gfx.y = 13 + yOffset
gfx.setpixel(0.34901960784314, 0.37647058823529, 0.36470588235294)
gfx.x = 5 + xOffset
gfx.y = 14 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 6 + xOffset
gfx.y = yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.y = 1 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 6 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 6 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.34509803921569, 0.38039215686275, 0.36862745098039)
gfx.x = 6 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.43529411764706, 0.46274509803922, 0.45098039215686)
gfx.x = 6 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.94509803921569, 0.94509803921569, 0.94509803921569)
gfx.x = 6 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(1.0, 1.0, 1.0)
gfx.x = 6 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(1.0, 1.0, 1.0)
gfx.x = 6 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.87058823529412, 0.87843137254902, 0.87843137254902)
gfx.x = 6 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.52156862745098, 0.54509803921569, 0.53725490196078)
gfx.x = 6 + xOffset
gfx.y = 10 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.38823529411765)
gfx.x = 6 + xOffset
gfx.y = 11 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 6 + xOffset
gfx.y = 12 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 6 + xOffset
gfx.y = 13 + yOffset
gfx.setpixel(0.34901960784314, 0.37647058823529, 0.36470588235294)
gfx.x = 6 + xOffset
gfx.y = 14 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 7 + xOffset
gfx.y = yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.y = 1 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 7 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 7 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.34509803921569, 0.38039215686275, 0.36470588235294)
gfx.x = 7 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.43529411764706, 0.46274509803922, 0.45098039215686)
gfx.x = 7 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.94901960784314, 0.95294117647059, 0.95294117647059)
gfx.x = 7 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(1.0, 1.0, 1.0)
gfx.x = 7 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.90196078431373, 0.90588235294118, 0.90196078431373)
gfx.x = 7 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.6, 0.6156862745098, 0.61176470588235)
gfx.x = 7 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.3921568627451, 0.42352941176471, 0.41176470588235)
gfx.x = 7 + xOffset
gfx.y = 10 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 7 + xOffset
gfx.y = 11 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 7 + xOffset
gfx.y = 12 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 7 + xOffset
gfx.y = 13 + yOffset
gfx.setpixel(0.34901960784314, 0.37647058823529, 0.36470588235294)
gfx.x = 7 + xOffset
gfx.y = 14 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 8 + xOffset
gfx.y = yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.y = 1 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 8 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 8 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.34509803921569, 0.37647058823529, 0.36470588235294)
gfx.x = 8 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.43529411764706, 0.46274509803922, 0.45490196078431)
gfx.x = 8 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.92156862745098, 0.92549019607843, 0.92549019607843)
gfx.x = 8 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.85490196078431, 0.86274509803922, 0.85882352941176)
gfx.x = 8 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.53725490196078, 0.56078431372549, 0.55294117647059)
gfx.x = 8 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.36470588235294, 0.4, 0.38823529411765)
gfx.x = 8 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.36078431372549, 0.3921568627451, 0.38039215686275)
gfx.x = 8 + xOffset
gfx.y = 10 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 8 + xOffset
gfx.y = 11 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 8 + xOffset
gfx.y = 12 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 8 + xOffset
gfx.y = 13 + yOffset
gfx.setpixel(0.34901960784314, 0.37647058823529, 0.36470588235294)
gfx.x = 8 + xOffset
gfx.y = 14 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 9 + xOffset
gfx.y = yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.y = 1 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 9 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.36862745098039, 0.39607843137255, 0.3843137254902)
gfx.x = 9 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.35294117647059, 0.3843137254902, 0.37254901960784)
gfx.x = 9 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.41176470588235, 0.43921568627451, 0.42745098039216)
gfx.x = 9 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.67843137254902, 0.69411764705882, 0.69019607843137)
gfx.x = 9 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.49803921568627, 0.52549019607843, 0.51764705882353)
gfx.x = 9 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 9 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 9 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 9 + xOffset
gfx.y = 10 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 9 + xOffset
gfx.y = 11 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 9 + xOffset
gfx.y = 12 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 9 + xOffset
gfx.y = 13 + yOffset
gfx.setpixel(0.34901960784314, 0.37647058823529, 0.36470588235294)
gfx.x = 9 + xOffset
gfx.y = 14 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 10 + xOffset
gfx.y = yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.y = 1 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 10 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 10 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 10 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 10 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.3843137254902, 0.4156862745098, 0.40392156862745)
gfx.x = 10 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 10 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 10 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 10 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 10 + xOffset
gfx.y = 10 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 10 + xOffset
gfx.y = 11 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 10 + xOffset
gfx.y = 12 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 10 + xOffset
gfx.y = 13 + yOffset
gfx.setpixel(0.34901960784314, 0.37647058823529, 0.36470588235294)
gfx.x = 10 + xOffset
gfx.y = 14 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 11 + xOffset
gfx.y = yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.y = 1 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 11 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 11 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 11 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 11 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.36078431372549, 0.3921568627451, 0.38039215686275)
gfx.x = 11 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 11 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 11 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 11 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 11 + xOffset
gfx.y = 10 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 11 + xOffset
gfx.y = 11 + yOffset
gfx.setpixel(0.36470588235294, 0.39607843137255, 0.3843137254902)
gfx.x = 11 + xOffset
gfx.y = 12 + yOffset
gfx.setpixel(0.36470588235294, 0.4, 0.38823529411765)
gfx.x = 11 + xOffset
gfx.y = 13 + yOffset
gfx.setpixel(0.34509803921569, 0.37647058823529, 0.36470588235294)
gfx.x = 11 + xOffset
gfx.y = 14 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 12 + xOffset
gfx.y = yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.y = 1 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 12 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 12 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 12 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 12 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 12 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 12 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 12 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 12 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 12 + xOffset
gfx.y = 10 + yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.x = 12 + xOffset
gfx.y = 11 + yOffset
gfx.setpixel(0.36470588235294, 0.4, 0.38823529411765)
gfx.x = 12 + xOffset
gfx.y = 12 + yOffset
gfx.setpixel(0.36862745098039, 0.40392156862745, 0.3921568627451)
gfx.x = 12 + xOffset
gfx.y = 13 + yOffset
gfx.setpixel(0.34901960784314, 0.38039215686275, 0.36862745098039)
gfx.x = 12 + xOffset
gfx.y = 14 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 13 + xOffset
gfx.y = yOffset
gfx.setpixel(0.36862745098039, 0.4, 0.38823529411765)
gfx.y = 1 + yOffset
gfx.setpixel(0.34901960784314, 0.38039215686275, 0.36862745098039)
gfx.x = 13 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.34509803921569, 0.37647058823529, 0.36470588235294)
gfx.x = 13 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.34901960784314, 0.37647058823529, 0.36470588235294)
gfx.x = 13 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.34901960784314, 0.37647058823529, 0.36470588235294)
gfx.x = 13 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.34901960784314, 0.37647058823529, 0.36470588235294)
gfx.x = 13 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.34901960784314, 0.37647058823529, 0.36470588235294)
gfx.x = 13 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.34901960784314, 0.37647058823529, 0.36470588235294)
gfx.x = 13 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.34901960784314, 0.37647058823529, 0.36470588235294)
gfx.x = 13 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.34901960784314, 0.37647058823529, 0.36470588235294)
gfx.x = 13 + xOffset
gfx.y = 10 + yOffset
gfx.setpixel(0.34901960784314, 0.37647058823529, 0.36470588235294)
gfx.x = 13 + xOffset
gfx.y = 11 + yOffset
gfx.setpixel(0.34509803921569, 0.37647058823529, 0.36470588235294)
gfx.x = 13 + xOffset
gfx.y = 12 + yOffset
gfx.setpixel(0.34901960784314, 0.38039215686275, 0.36862745098039)
gfx.x = 13 + xOffset
gfx.y = 13 + yOffset
gfx.setpixel(0.32549019607843, 0.35294117647059, 0.34117647058824)
gfx.x = 13 + xOffset
gfx.y = 14 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 14 + xOffset
gfx.y = 1 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 14 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 14 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 14 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 14 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 14 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 14 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 14 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 14 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 14 + xOffset
gfx.y = 10 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 14 + xOffset
gfx.y = 11 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 14 + xOffset
gfx.y = 12 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 14 + xOffset
gfx.y = 13 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 14 + xOffset
gfx.y = 14 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
end
function drawLeftArrow()
local xOffset = gfx.x
local yOffset = gfx.y
gfx.x = 1 + xOffset
gfx.y = 1 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 1 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 1 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.10196078431373, 0.10196078431373, 0.10196078431373)
gfx.x = 1 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.18823529411765, 0.1921568627451, 0.1921568627451)
gfx.x = 1 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.10196078431373, 0.10196078431373, 0.10196078431373)
gfx.x = 1 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 1 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 1 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 1 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 2 + xOffset
gfx.y = 1 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 2 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.07843137254902, 0.07843137254902, 0.074509803921569)
gfx.x = 2 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.24313725490196, 0.25882352941176, 0.25882352941176)
gfx.x = 2 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.45490196078431, 0.48627450980392, 0.49019607843137)
gfx.x = 2 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.24313725490196, 0.25882352941176, 0.25882352941176)
gfx.x = 2 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.07843137254902, 0.07843137254902, 0.074509803921569)
gfx.x = 2 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 2 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 2 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 3 + xOffset
gfx.y = 1 + yOffset
gfx.setpixel(0.07843137254902, 0.07843137254902, 0.07843137254902)
gfx.x = 3 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.19607843137255, 0.2078431372549, 0.2078431372549)
gfx.x = 3 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.47450980392157, 0.51372549019608, 0.51372549019608)
gfx.x = 3 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.56078431372549, 0.61176470588235, 0.61176470588235)
gfx.x = 3 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.47450980392157, 0.51372549019608, 0.51372549019608)
gfx.x = 3 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.19607843137255, 0.2078431372549, 0.2078431372549)
gfx.x = 3 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.07843137254902, 0.07843137254902, 0.07843137254902)
gfx.x = 3 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.090196078431373, 0.090196078431373, 0.090196078431373)
gfx.x = 3 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 4 + xOffset
gfx.y = 1 + yOffset
gfx.setpixel(0.19607843137255, 0.2078431372549, 0.2078431372549)
gfx.x = 4 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.44313725490196, 0.47843137254902, 0.47843137254902)
gfx.x = 4 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.56862745098039, 0.6156862745098, 0.61176470588235)
gfx.x = 4 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.57647058823529, 0.62352941176471, 0.62352941176471)
gfx.x = 4 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.56862745098039, 0.6156862745098, 0.61176470588235)
gfx.x = 4 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.44313725490196, 0.47843137254902, 0.47843137254902)
gfx.x = 4 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.19607843137255, 0.2078431372549, 0.2078431372549)
gfx.x = 4 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 4 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 5 + xOffset
gfx.y = 1 + yOffset
gfx.setpixel(0.30196078431373, 0.32156862745098, 0.32156862745098)
gfx.x = 5 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.49411764705882, 0.53725490196078, 0.53725490196078)
gfx.x = 5 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.51764705882353, 0.56470588235294, 0.56470588235294)
gfx.x = 5 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.51372549019608, 0.55686274509804, 0.55686274509804)
gfx.x = 5 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.51764705882353, 0.56470588235294, 0.56470588235294)
gfx.x = 5 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.49411764705882, 0.53725490196078, 0.53725490196078)
gfx.x = 5 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.30196078431373, 0.32156862745098, 0.32156862745098)
gfx.x = 5 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.098039215686275, 0.098039215686275, 0.098039215686275)
gfx.x = 5 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 6 + xOffset
gfx.y = 1 + yOffset
gfx.setpixel(0.11764705882353, 0.12156862745098, 0.12156862745098)
gfx.x = 6 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.13725490196078, 0.14117647058824, 0.14117647058824)
gfx.x = 6 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.13333333333333, 0.13725490196078, 0.13725490196078)
gfx.x = 6 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.13333333333333, 0.13725490196078, 0.13725490196078)
gfx.x = 6 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.13333333333333, 0.13725490196078, 0.13725490196078)
gfx.x = 6 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.13725490196078, 0.14117647058824, 0.14117647058824)
gfx.x = 6 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.11764705882353, 0.12156862745098, 0.12156862745098)
gfx.x = 6 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 6 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 7 + xOffset
gfx.y = 1 + yOffset
gfx.setpixel(0.07843137254902, 0.074509803921569, 0.074509803921569)
gfx.x = 7 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.070588235294118, 0.066666666666667, 0.066666666666667)
gfx.x = 7 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.070588235294118, 0.066666666666667, 0.066666666666667)
gfx.x = 7 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.070588235294118, 0.070588235294118, 0.070588235294118)
gfx.x = 7 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.070588235294118, 0.066666666666667, 0.066666666666667)
gfx.x = 7 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.070588235294118, 0.066666666666667, 0.066666666666667)
gfx.x = 7 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.07843137254902, 0.074509803921569, 0.074509803921569)
gfx.x = 7 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 7 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 8 + xOffset
gfx.y = 1 + yOffset
gfx.setpixel(0.086274509803922, 0.090196078431373, 0.090196078431373)
gfx.x = 8 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.090196078431373, 0.090196078431373, 0.090196078431373)
gfx.x = 8 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.090196078431373, 0.090196078431373, 0.090196078431373)
gfx.x = 8 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.090196078431373, 0.090196078431373, 0.090196078431373)
gfx.x = 8 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.090196078431373, 0.090196078431373, 0.090196078431373)
gfx.x = 8 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.090196078431373, 0.090196078431373, 0.090196078431373)
gfx.x = 8 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.086274509803922, 0.090196078431373, 0.090196078431373)
gfx.x = 8 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 8 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 9 + xOffset
gfx.y = 1 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 9 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 9 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 9 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 9 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 9 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 9 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 9 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 9 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
end
function drawRightArrow()
local xOffset = gfx.x
local yOffset = gfx.y
gfx.x = 1 + xOffset
gfx.y = 1 + yOffset
gfx.setpixel(0.07843137254902, 0.074509803921569, 0.074509803921569)
gfx.x = 1 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.070588235294118, 0.066666666666667, 0.066666666666667)
gfx.x = 1 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.070588235294118, 0.066666666666667, 0.066666666666667)
gfx.x = 1 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.070588235294118, 0.070588235294118, 0.070588235294118)
gfx.x = 1 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.070588235294118, 0.066666666666667, 0.066666666666667)
gfx.x = 1 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.070588235294118, 0.066666666666667, 0.066666666666667)
gfx.x = 1 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.07843137254902, 0.074509803921569, 0.074509803921569)
gfx.x = 1 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 1 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 2 + xOffset
gfx.y = 1 + yOffset
gfx.setpixel(0.11764705882353, 0.12156862745098, 0.12156862745098)
gfx.x = 2 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.13725490196078, 0.14117647058824, 0.14117647058824)
gfx.x = 2 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.13333333333333, 0.13725490196078, 0.13725490196078)
gfx.x = 2 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.13333333333333, 0.13725490196078, 0.13725490196078)
gfx.x = 2 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.13333333333333, 0.13725490196078, 0.13725490196078)
gfx.x = 2 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.13725490196078, 0.14117647058824, 0.14117647058824)
gfx.x = 2 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.11764705882353, 0.12156862745098, 0.12156862745098)
gfx.x = 2 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 2 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 3 + xOffset
gfx.y = 1 + yOffset
gfx.setpixel(0.30196078431373, 0.32156862745098, 0.32156862745098)
gfx.x = 3 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.49411764705882, 0.53725490196078, 0.53725490196078)
gfx.x = 3 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.51764705882353, 0.56470588235294, 0.56470588235294)
gfx.x = 3 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.51372549019608, 0.55686274509804, 0.55686274509804)
gfx.x = 3 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.51764705882353, 0.56470588235294, 0.56470588235294)
gfx.x = 3 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.49411764705882, 0.53725490196078, 0.53725490196078)
gfx.x = 3 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.30196078431373, 0.32156862745098, 0.32156862745098)
gfx.x = 3 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.098039215686275, 0.098039215686275, 0.098039215686275)
gfx.x = 3 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 4 + xOffset
gfx.y = 1 + yOffset
gfx.setpixel(0.19607843137255, 0.2078431372549, 0.2078431372549)
gfx.x = 4 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.44313725490196, 0.47843137254902, 0.47843137254902)
gfx.x = 4 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.56862745098039, 0.6156862745098, 0.61176470588235)
gfx.x = 4 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.57647058823529, 0.62352941176471, 0.62352941176471)
gfx.x = 4 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.56862745098039, 0.6156862745098, 0.61176470588235)
gfx.x = 4 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.44313725490196, 0.47843137254902, 0.47843137254902)
gfx.x = 4 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.19607843137255, 0.2078431372549, 0.2078431372549)
gfx.x = 4 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 4 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 5 + xOffset
gfx.y = 1 + yOffset
gfx.setpixel(0.07843137254902, 0.07843137254902, 0.07843137254902)
gfx.x = 5 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.19607843137255, 0.2078431372549, 0.2078431372549)
gfx.x = 5 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.47450980392157, 0.51372549019608, 0.51372549019608)
gfx.x = 5 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.56078431372549, 0.61176470588235, 0.61176470588235)
gfx.x = 5 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.47450980392157, 0.51372549019608, 0.51372549019608)
gfx.x = 5 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.19607843137255, 0.2078431372549, 0.2078431372549)
gfx.x = 5 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.07843137254902, 0.07843137254902, 0.07843137254902)
gfx.x = 5 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.090196078431373, 0.090196078431373, 0.090196078431373)
gfx.x = 5 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 6 + xOffset
gfx.y = 1 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 6 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.07843137254902, 0.07843137254902, 0.074509803921569)
gfx.x = 6 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.24313725490196, 0.25882352941176, 0.25882352941176)
gfx.x = 6 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.45490196078431, 0.48627450980392, 0.49019607843137)
gfx.x = 6 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.24313725490196, 0.25882352941176, 0.25882352941176)
gfx.x = 6 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.07843137254902, 0.07843137254902, 0.074509803921569)
gfx.x = 6 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 6 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 6 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 7 + xOffset
gfx.y = 1 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 7 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 7 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.10196078431373, 0.10196078431373, 0.10196078431373)
gfx.x = 7 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.18823529411765, 0.1921568627451, 0.1921568627451)
gfx.x = 7 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.10196078431373, 0.10196078431373, 0.10196078431373)
gfx.x = 7 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 7 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 7 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 7 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 8 + xOffset
gfx.y = 1 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 8 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 8 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 8 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.086274509803922, 0.082352941176471, 0.082352941176471)
gfx.x = 8 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 8 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 8 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 8 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.086274509803922, 0.086274509803922, 0.086274509803922)
gfx.x = 8 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 9 + xOffset
gfx.y = 1 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 9 + xOffset
gfx.y = 2 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 9 + xOffset
gfx.y = 3 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 9 + xOffset
gfx.y = 4 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 9 + xOffset
gfx.y = 5 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 9 + xOffset
gfx.y = 6 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 9 + xOffset
gfx.y = 7 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 9 + xOffset
gfx.y = 8 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
gfx.x = 9 + xOffset
gfx.y = 9 + yOffset
gfx.setpixel(0.0, 0.0, 0.0)
end
local function hex2rgb(arg)
local r, g, b = arg:match('(..)(..)(..)')
r = tonumber(r, 16)/255
g = tonumber(g, 16)/255
b = tonumber(b, 16)/255
return r, g, b
end
local function setColor(hexColor)
local r, g, b = hex2rgb(hexColor)
gfx.set(r, g, b, 1)
end
--[[ window ]]--
function setDrawColorToBackground()
setColor("242424")
end
--[[ buttons ]]--
function setDrawColorToNormalButton()
setColor("2D2D2D")
end
function setDrawColorToHighlightedButton()
setColor("474747")
end
--
function setDrawColorToSelectedChordTypeButton()
setColor("474747")
end
function setDrawColorToHighlightedSelectedChordTypeButton()
setColor("717171")
end
--
function setDrawColorToSelectedChordTypeAndScaleNoteButton()
setColor("DCDCDC")
end
function setDrawColorToHighlightedSelectedChordTypeAndScaleNoteButton()
setColor("FFFFFF")
end
--
function setDrawColorToOutOfScaleButton()
setColor("121212")
end
function setDrawColorToHighlightedOutOfScaleButton()
setColor("474747")
end
--
function setDrawColorToButtonOutline()
setColor("1D1D1D")
end
--[[ button text ]]--
function setDrawColorToNormalButtonText()
setColor("D7D7D7")
end
function setDrawColorToHighlightedButtonText()
setColor("EEEEEE")
end
--
function setDrawColorToSelectedChordTypeButtonText()
setColor("F1F1F1")
end
function setDrawColorToHighlightedSelectedChordTypeButtonText()
setColor("FDFDFD")
end
--
function setDrawColorToSelectedChordTypeAndScaleNoteButtonText()
setColor("121212")
end
function setDrawColorToHighlightedSelectedChordTypeAndScaleNoteButtonText()
setColor("000000")
end
--[[ buttons ]]--
function setDrawColorToHeaderOutline()
setColor("151515")
end
function setDrawColorToHeaderBackground()
setColor("242424")
end
function setDrawColorToHeaderText()
setColor("818181")
end
--[[ frame ]]--
function setDrawColorToFrameOutline()
setColor("0D0D0D")
end
function setDrawColorToFrameBackground()
setColor("181818")
end
--[[ dropdown ]]--
function setDrawColorToDropdownOutline()
setColor("090909")
end
function setDrawColorToDropdownBackground()
setColor("1D1D1D")
end
function setDrawColorToDropdownText()
setColor("D7D7D7")
end
--[[ valuebox ]]--
function setDrawColorToValueBoxOutline()
setColor("090909")
end
function setDrawColorToValueBoxBackground()
setColor("161616")
end
function setDrawColorToValueBoxText()
setColor("9F9F9F")
end
--[[ text ]]--
function setDrawColorToText()
setColor("878787")
end
--[[ debug ]]--
function setDrawColorToRed()
setColor("FF0000")
end
--[[
function setDrawColorToBackground()
local r, g, b
local backgroundColor = {36, 36, 36, 1} -- #242424
gfx.set(table.unpack(backgroundColor))
end
function setDrawColorToNormalButton()
local backgroundColor = {45, 45, 45, 1} -- #2D2D2D
gfx.set(table.unpack(backgroundColor))
end
function setDrawColorToHighlightedButton()
local backgroundColor = {71, 71, 71, 1} -- #474747
gfx.set(table.unpack(backgroundColor))
end
function setDrawColorToSelectedButton()
local backgroundColor = {220, 220, 220, 1} -- #DCDCDC
gfx.set(table.unpack(backgroundColor))
end
]]--
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
Docker = {}
Docker.__index = Docker
function Docker:new()
local self = {}
setmetatable(self, Docker)
return self
end
local function dockWindow()
local dockState = getDockState()
gfx.dock(dockState)
setWindowShouldBeDocked(true)
guiShouldBeUpdated = true
end
function Docker:drawDockWindowContextMenu()
setPositionAtMouseCursor()
local selectedIndex = gfx.showmenu("dock window")
if selectedIndex <= 0 then
return
end
dockWindow()
gfx.mouse_cap = 0
end
local function undockWindow()
setWindowShouldBeDocked(false)
gfx.dock(0)
guiShouldBeUpdated = true
end
function Docker:drawUndockWindowContextMenu()
setPositionAtMouseCursor()
local selectedIndex = gfx.showmenu("undock window")
if selectedIndex <= 0 then
return
end
undockWindow()
gfx.mouse_cap = 0
end
function Docker:update()
if rightMouseButtonIsHeldDown() and windowIsDocked() then
self:drawUndockWindowContextMenu()
end
if rightMouseButtonIsHeldDown() and windowIsNotDocked() then
self:drawDockWindowContextMenu()
end
end
HitArea = {}
HitArea.__index = HitArea
function HitArea:new(x, y, width, height)
local self = {}
setmetatable(self, HitArea)
self.x = x
self.y = y
self.width = width
self.height = height
return self
end
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
OctaveValueBox = {}
OctaveValueBox.__index = OctaveValueBox
function OctaveValueBox:new(x, y, width, height)
local self = {}
setmetatable(self, OctaveValueBox)
self.x = x
self.y = y
self.width = width
self.height = height
return self
end
function OctaveValueBox:drawRectangle()
setDrawColorToValueBoxBackground()
gfx.rect(self.x, self.y, self.width, self.height)
end
function OctaveValueBox:drawRectangleOutline()
setDrawColorToValueBoxOutline()
gfx.rect(self.x-1, self.y-1, self.width+1, self.height+1, false)
end
function OctaveValueBox:drawRectangles()
self:drawRectangle()
self:drawRectangleOutline()
end
function OctaveValueBox:drawLeftArrow()
gfx.x = self.x + 2
gfx.y = self.y + 2
drawLeftArrow()
end
function OctaveValueBox:drawRightArrow()
local imageWidth = 9
gfx.x = self.x + self.width - imageWidth - 3
gfx.y = self.y + 2
drawRightArrow()
end
function OctaveValueBox:drawImages()
self:drawLeftArrow()
self:drawRightArrow()
end
function OctaveValueBox:drawText()
local octaveText = getOctave()
setDrawColorToValueBoxText()
local stringWidth, stringHeight = gfx.measurestr(octaveText)
gfx.x = self.x + ((self.width - stringWidth) / 2)
gfx.y = self.y + ((self.height - stringHeight) / 2)
gfx.drawstr(octaveText)
end
local hitAreaWidth = 18
local function leftButtonHasBeenClicked(valueBox)
local hitArea = HitArea:new(valueBox.x-1, valueBox.y-1, hitAreaWidth, valueBox.height+1)
return mouseIsHoveringOver(hitArea) and leftMouseButtonIsHeldDown()
end
local function rightButtonHasBeenClicked(valueBox)
local hitArea = HitArea:new(valueBox.x+valueBox.width-hitAreaWidth, valueBox.y-1, hitAreaWidth, valueBox.height+1)
return mouseIsHoveringOver(hitArea) and leftMouseButtonIsHeldDown()
end
function OctaveValueBox:update()
self:drawRectangles()
self:drawImages()
if mouseButtonIsNotPressedDown and leftButtonHasBeenClicked(self) then
mouseButtonIsNotPressedDown = false
decrementOctaveAction()
end
if mouseButtonIsNotPressedDown and rightButtonHasBeenClicked(self) then
mouseButtonIsNotPressedDown = false
incrementOctaveAction()
end
self:drawText()
end
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
Label = {}
Label.__index = Label
function Label:new(x, y, width, height, getTextCallback)
local self = {}
setmetatable(self, Label)
self.x = x
self.y = y
self.width = width
self.height = height
self.getTextCallback = getTextCallback
return self
end
function Label:drawRedOutline()
setDrawColorToRed()
gfx.rect(self.x, self.y, self.width, self.height, false)
end
function Label:drawText(text)
setDrawColorToText()
local stringWidth, stringHeight = gfx.measurestr(text)
gfx.x = self.x + ((self.width - stringWidth) / 2)
gfx.y = self.y + ((self.height - stringHeight) / 2)
gfx.drawstr(text)
end
function Label:update()
--self:drawRedOutline()
local text = self.getTextCallback()
self:drawText(text)
end
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
Header = {}
Header.__index = Header
local radius = 5
function Header:new(x, y, width, height, getTextCallback)
local self = {}
setmetatable(self, Header)
self.x = x
self.y = y
self.width = width
self.height = height
self.getTextCallback = getTextCallback
return self
end
function Header:drawCorners(offset)
gfx.circle(self.x + radius + offset, self.y + radius + offset, radius, true)
gfx.circle(self.x + self.width - radius - offset, self.y + radius + offset, radius, true)
end
function Header:drawEnds(offset)
gfx.rect(self.x + offset, self.y + radius + offset, radius, self.height - radius * 2 - 2 * offset, true)
gfx.rect(self.x + self.width - radius - offset, self.y + radius + offset, radius + 1, self.height - radius * 2 - 2 * offset, true)
end
function Header:drawBodyAndSides(offset)
gfx.rect(self.x + radius + offset, self.y + offset, self.width - radius * 2 - 2 * offset, self.height - radius - 2 * offset, true)
end
function Header:drawHeaderOutline()
setDrawColorToHeaderOutline()
self:drawCorners(0)
self:drawEnds(0)
self:drawBodyAndSides(0)
end
function Header:drawRoundedRectangle()
setDrawColorToHeaderBackground()
self:drawCorners(1)
self:drawEnds(1)
self:drawBodyAndSides(1)
end
function Header:drawRoundedRectangles()
self:drawHeaderOutline()
self:drawRoundedRectangle()
end
function Header:drawText(text)
setDrawColorToHeaderText()
local stringWidth, stringHeight = gfx.measurestr(text)
gfx.x = self.x + ((self.width + 4 * 1 - stringWidth) / 2)
gfx.y = self.y + ((self.height - 4 * 1 - stringHeight) / 2)
gfx.drawstr(text)
end
function Header:update()
self:drawRoundedRectangles()
local text = self.getTextCallback()
self:drawText(text)
end
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
Frame = {}
Frame.__index = Frame
local radius = 10
function Frame:new(x, y, width, height)
local self = {}
setmetatable(self, Frame)
self.x = x
self.y = y
self.width = width
self.height = height
return self
end
function Frame:drawCorners(offset)
gfx.circle(self.x + radius + offset, self.y + radius + offset, radius, true)
gfx.circle(self.x + self.width - radius - offset, self.y + radius + offset, radius, true)
gfx.circle(self.x + radius + offset, self.y + self.height - radius - offset, radius, true)
gfx.circle(self.x + self.width - radius - offset, self.y + self.height - radius - offset, radius, true)
end
function Frame:drawEnds(offset)
gfx.rect(self.x + offset, self.y + radius + offset, radius, self.height - radius * 2, true)
gfx.rect(self.x + self.width - radius - offset, self.y + radius - offset, radius + 1, self.height - radius * 2, true)
end
function Frame:drawBodyAndSides(offset)
gfx.rect(self.x + radius + offset, self.y + offset, self.width - radius * 2 - 2 * offset, self.height + 1 - 2 * offset, true)
end
function Frame:drawFrameOutline()
setDrawColorToFrameOutline()
self:drawCorners(0)
self:drawEnds(0)
self:drawBodyAndSides(0)
end
function Frame:drawRectangle()
setDrawColorToFrameBackground()
self:drawCorners(1)
self:drawEnds(1)
self:drawBodyAndSides(1)
end
function Frame:drawRectangles()
self:drawFrameOutline()
self:drawRectangle()
end
function Frame:update()
self:drawRectangles()
end
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
Dropdown = {}
Dropdown.__index = Dropdown
function Dropdown:new(x, y, width, height, options, defaultOptionIndex, onSelectionCallback)
local self = {}
setmetatable(self, Dropdown)
self.x = x
self.y = y
self.width = width
self.height = height
self.options = options
self.selectedIndex = defaultOptionIndex
self.onSelectionCallback = onSelectionCallback
self.dropdownList = {}
self:updateDropdownList()
return self
end
function Dropdown:drawRectangle()
setDrawColorToDropdownBackground()
gfx.rect(self.x, self.y, self.width, self.height)
end
function Dropdown:drawRectangleOutline()
setDrawColorToDropdownOutline()
gfx.rect(self.x-1, self.y-1, self.width+1, self.height+1, false)
end
function Dropdown:drawRectangles()
self:drawRectangle()
self:drawRectangleOutline()
end
function Dropdown:drawText()
local text = self.options[self.selectedIndex]
setDrawColorToDropdownText()
local stringWidth, stringHeight = gfx.measurestr(text)
gfx.x = self.x + 7
gfx.y = self.y + ((self.height - stringHeight) / 2)
gfx.drawstr(text)
end
function Dropdown:drawImage()
local imageWidth = 14
gfx.x = self.x + self.width - imageWidth - 1
gfx.y = self.y
drawDropdownIcon()
end
local function dropdownHasBeenClicked(dropdown)
return mouseIsHoveringOver(dropdown) and leftMouseButtonIsHeldDown()
end
function Dropdown:updateDropdownList()
self.dropdownList = {}
for index, option in pairs(self.options) do
if (self.selectedIndex == index) then
table.insert(self.dropdownList, "!" .. option)
else
table.insert(self.dropdownList, option)
end
end
end
function Dropdown:openMenu()
setPositionAtMouseCursor()
local selectedIndex = gfx.showmenu(table.concat(self.dropdownList,"|"))
if selectedIndex <= 0 then
return
end
self.selectedIndex = selectedIndex
self.onSelectionCallback(selectedIndex)
self:updateDropdownList()
end
function Dropdown:update()
self:drawRectangles()
self:drawText()
self:drawImage()
if mouseButtonIsNotPressedDown and dropdownHasBeenClicked(self) then
mouseButtonIsNotPressedDown = false
self:openMenu()
end
end
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
ChordInversionValueBox = {}
ChordInversionValueBox.__index = ChordInversionValueBox
function ChordInversionValueBox:new(x, y, width, height)
local self = {}
setmetatable(self, ChordInversionValueBox)
self.x = x
self.y = y
self.width = width
self.height = height
return self
end
function ChordInversionValueBox:drawRectangle()
setDrawColorToValueBoxBackground()
gfx.rect(self.x, self.y, self.width, self.height)
end
function ChordInversionValueBox:drawRectangleOutline()
setDrawColorToValueBoxOutline()
gfx.rect(self.x-1, self.y-1, self.width+1, self.height+1, false)
end
function ChordInversionValueBox:drawRectangles()
self:drawRectangle()
self:drawRectangleOutline()
end
function ChordInversionValueBox:drawLeftArrow()
gfx.x = self.x + 2
gfx.y = self.y + 2
drawLeftArrow()
end
function ChordInversionValueBox:drawRightArrow()
local imageWidth = 9
gfx.x = self.x + self.width - imageWidth - 3
gfx.y = self.y + 2
drawRightArrow()
end
function ChordInversionValueBox:drawImages()
self:drawLeftArrow()
self:drawRightArrow()
end
function ChordInversionValueBox:drawText()
local selectedScaleNote = getSelectedScaleNote()
local chordInversionText = getChordInversionState(selectedScaleNote)
if chordInversionText > -1 then
chordInversionText = "0" .. chordInversionText
end
setDrawColorToValueBoxText()
local stringWidth, stringHeight = gfx.measurestr(chordInversionText)
gfx.x = self.x + ((self.width - stringWidth) / 2)
gfx.y = self.y + ((self.height - stringHeight) / 2)
gfx.drawstr(chordInversionText)
end
local hitAreaWidth = 18
local function leftButtonHasBeenClicked(valueBox)
local hitArea = HitArea:new(valueBox.x-1, valueBox.y-1, hitAreaWidth, valueBox.height+1)
return mouseIsHoveringOver(hitArea) and leftMouseButtonIsHeldDown()
end
local function rightButtonHasBeenClicked(valueBox)
local hitArea = HitArea:new(valueBox.x+valueBox.width-hitAreaWidth, valueBox.y-1, hitAreaWidth, valueBox.height+1)
return mouseIsHoveringOver(hitArea) and leftMouseButtonIsHeldDown()
end
local function shiftModifierIsHeldDown()
return gfx.mouse_cap & 8 == 8
end
function ChordInversionValueBox:onLeftButtonPress()
decrementChordInversion()
previewScaleChord()
end
function ChordInversionValueBox:onLeftButtonShiftPress()
decrementChordInversionAction()
end
function ChordInversionValueBox:onRightButtonPress()
incrementChordInversion()
previewScaleChord()
end
function ChordInversionValueBox:onRightButtonShiftPress()
incrementChordInversionAction()
end
function ChordInversionValueBox:update()
self:drawRectangles()
self:drawImages()
if mouseButtonIsNotPressedDown and leftButtonHasBeenClicked(self) then
mouseButtonIsNotPressedDown = false
if shiftModifierIsHeldDown() then
self:onLeftButtonShiftPress()
else
self:onLeftButtonPress()
end
end
if mouseButtonIsNotPressedDown and rightButtonHasBeenClicked(self) then
mouseButtonIsNotPressedDown = false
if shiftModifierIsHeldDown() then
self:onRightButtonShiftPress()
else
self:onRightButtonPress()
end
end
self:drawText()
end
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
ChordButton = {}
ChordButton.__index = ChordButton
function ChordButton:new(text, x, y, width, height, scaleNoteIndex, chordTypeIndex, chordIsInScale)
local self = {}
setmetatable(self, ChordButton)
self.text = text
self.x = x
self.y = y
self.width = width
self.height = height
self.scaleNoteIndex = scaleNoteIndex
self.chordTypeIndex = chordTypeIndex
self.chordIsInScale = chordIsInScale
return self
end
function ChordButton:isSelectedChordType()
local selectedScaleNote = getSelectedScaleNote()
local selectedChordType = getSelectedChordType(self.scaleNoteIndex)
local chordTypeIsSelected = (tonumber(self.chordTypeIndex) == tonumber(selectedChordType))
local scaleNoteIsNotSelected = (tonumber(self.scaleNoteIndex) ~= tonumber(selectedScaleNote))
return chordTypeIsSelected and scaleNoteIsNotSelected
end
function ChordButton:isSelectedChordTypeAndSelectedScaleNote()
local selectedScaleNote = getSelectedScaleNote()
local selectedChordType = getSelectedChordType(self.scaleNoteIndex)
local chordTypeIsSelected = (tonumber(self.chordTypeIndex) == tonumber(selectedChordType))
local scaleNoteIsSelected = (tonumber(self.scaleNoteIndex) == tonumber(selectedScaleNote))
return chordTypeIsSelected and scaleNoteIsSelected
end
function ChordButton:drawButtonRectangle()
if self:isSelectedChordTypeAndSelectedScaleNote() then
if mouseIsHoveringOver(self) then
setDrawColorToHighlightedSelectedChordTypeAndScaleNoteButton()
else
setDrawColorToSelectedChordTypeAndScaleNoteButton()
end
elseif self:isSelectedChordType() then
if mouseIsHoveringOver(self) then
setDrawColorToHighlightedSelectedChordTypeButton()
else
setDrawColorToSelectedChordTypeButton()
end
else
if mouseIsHoveringOver(self) then
setDrawColorToHighlightedButton()
else
if self.chordIsInScale then
setDrawColorToNormalButton()
else
setDrawColorToOutOfScaleButton()
end
end
end
gfx.rect(self.x, self.y, self.width, self.height)
end
function ChordButton:drawButtonOutline()
setDrawColorToButtonOutline()
gfx.rect(self.x-1, self.y-1, self.width+1, self.height+1, false)
end
function ChordButton:drawRectangles()
self:drawButtonRectangle()
self:drawButtonOutline()
end
function ChordButton:drawText()
if self:isSelectedChordTypeAndSelectedScaleNote() then
if mouseIsHoveringOver(self) then
setDrawColorToHighlightedSelectedChordTypeAndScaleNoteButtonText()
else
setDrawColorToSelectedChordTypeAndScaleNoteButtonText()
end
elseif self:isSelectedChordType() then
if mouseIsHoveringOver(self) then
setDrawColorToHighlightedSelectedChordTypeButtonText()
else
setDrawColorToSelectedChordTypeButtonText()
end
else
if mouseIsHoveringOver(self) then
setDrawColorToHighlightedButtonText()
else
setDrawColorToNormalButtonText()
end
end
local stringWidth, stringHeight = gfx.measurestr(self.text)
gfx.x = self.x + ((self.width - stringWidth) / 2)
gfx.y = self.y + ((self.height - stringHeight) / 2)
gfx.drawstr(self.text)
end
local function buttonHasBeenClicked(button)
return mouseIsHoveringOver(button) and leftMouseButtonIsHeldDown()
end
local function shiftModifierIsHeldDown()
return gfx.mouse_cap & 8 == 8
end
function ChordButton:onPress()
previewScaleChord()
end
function ChordButton:onShiftPress()
local chord = scaleChords[self.scaleNoteIndex][self.chordTypeIndex]
local actionDescription = "scale chord " .. self.scaleNoteIndex .. " (" .. chord.code .. ")"
playOrInsertScaleChord(actionDescription)
end
function ChordButton:update()
self:drawRectangles()
self:drawText()
if mouseButtonIsNotPressedDown and buttonHasBeenClicked(self) then
mouseButtonIsNotPressedDown = false
setSelectedScaleNote(self.scaleNoteIndex)
setSelectedChordType(self.scaleNoteIndex, self.chordTypeIndex)
if shiftModifierIsHeldDown() then
self:onShiftPress()
else
self:onPress()
end
end
end
inputCharacters = {}
inputCharacters["0"] = 48
inputCharacters["1"] = 49
inputCharacters["2"] = 50
inputCharacters["3"] = 51
inputCharacters["4"] = 52
inputCharacters["5"] = 53
inputCharacters["6"] = 54
inputCharacters["7"] = 55
inputCharacters["a"] = 97
inputCharacters["b"] = 98
inputCharacters["c"] = 99
inputCharacters["d"] = 100
inputCharacters["e"] = 101
inputCharacters["f"] = 102
inputCharacters["g"] = 103
inputCharacters["h"] = 104
inputCharacters["i"] = 105
inputCharacters["j"] = 106
inputCharacters["k"] = 107
inputCharacters["l"] = 108
inputCharacters["m"] = 109
inputCharacters["n"] = 110
inputCharacters["o"] = 111
inputCharacters["p"] = 112
inputCharacters["q"] = 113
inputCharacters["r"] = 114
inputCharacters["s"] = 115
inputCharacters["t"] = 116
inputCharacters["u"] = 117
inputCharacters["v"] = 118
inputCharacters["w"] = 119
inputCharacters["x"] = 120
inputCharacters["y"] = 121
inputCharacters["z"] = 122
inputCharacters["!"] = 33
inputCharacters["@"] = 64
inputCharacters["#"] = 35
inputCharacters["$"] = 36
inputCharacters["%"] = 37
inputCharacters["^"] = 94
inputCharacters["&"] = 38
inputCharacters["A"] = 65
inputCharacters["B"] = 66
inputCharacters["C"] = 67
inputCharacters["D"] = 68
inputCharacters["E"] = 69
inputCharacters["F"] = 70
inputCharacters["G"] = 71
inputCharacters["H"] = 72
inputCharacters["I"] = 73
inputCharacters["J"] = 74
inputCharacters["K"] = 75
inputCharacters["L"] = 76
inputCharacters["M"] = 77
inputCharacters["N"] = 78
inputCharacters["O"] = 79
inputCharacters["P"] = 80
inputCharacters["Q"] = 81
inputCharacters["R"] = 82
inputCharacters["S"] = 83
inputCharacters["T"] = 84
inputCharacters["U"] = 85
inputCharacters["V"] = 86
inputCharacters["W"] = 87
inputCharacters["X"] = 88
inputCharacters["Y"] = 89
inputCharacters["Z"] = 90
inputCharacters[","] = 44
inputCharacters["."] = 46
inputCharacters["<"] = 60
inputCharacters[">"] = 62
inputCharacters["ESC"] = 27
inputCharacters["LEFTARROW"] = 1818584692
inputCharacters["RIGHTARROW"] = 1919379572
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
function handleInput()
inputCharacter = gfx.getchar()
if inputCharacter == inputCharacters["LEFTARROW"] then
if activeTake()~= nil and activeMediaItem() ~= nil then
moveEditCursorPosition(-noteLength())
end
end
if inputCharacter == inputCharacters["RIGHTARROW"] then
if activeTake()~= nil and activeMediaItem() ~= nil then
moveEditCursorPosition(noteLength())
end
end
if inputCharacter == inputCharacters["ESC"] then
gfx.quit()
end
if inputCharacter == inputCharacters["0"] then
stopAllNotesFromPlaying()
end
--
if inputCharacter == inputCharacters["1"] then
previewScaleChordAction(1)
end
if inputCharacter == inputCharacters["2"] then
previewScaleChordAction(2)
end
if inputCharacter == inputCharacters["3"] then
previewScaleChordAction(3)
end
if inputCharacter == inputCharacters["4"] then
previewScaleChordAction(4)
end
if inputCharacter == inputCharacters["5"] then
previewScaleChordAction(5)
end
if inputCharacter == inputCharacters["6"] then
previewScaleChordAction(6)
end
if inputCharacter == inputCharacters["7"] then
previewScaleChordAction(7)
end
--
if inputCharacter == inputCharacters["!"] then
scaleChordAction(1)
end
if inputCharacter == inputCharacters["@"] then
scaleChordAction(2)
end
if inputCharacter == inputCharacters["#"] then
scaleChordAction(3)
end
if inputCharacter == inputCharacters["$"] then
scaleChordAction(4)
end
if inputCharacter == inputCharacters["%"] then
scaleChordAction(5)
end
if inputCharacter == inputCharacters["^"] then
scaleChordAction(6)
end
if inputCharacter == inputCharacters["&"] then
scaleChordAction(7)
end
--
if inputCharacter == inputCharacters["q"] then
previewHigherScaleNoteAction(1)
end
if inputCharacter == inputCharacters["w"] then
previewHigherScaleNoteAction(2)
end
if inputCharacter == inputCharacters["e"] then
previewHigherScaleNoteAction(3)
end
if inputCharacter == inputCharacters["r"] then
previewHigherScaleNoteAction(4)
end
if inputCharacter == inputCharacters["t"] then
previewHigherScaleNoteAction(5)
end
if inputCharacter == inputCharacters["y"] then
previewHigherScaleNoteAction(6)
end
if inputCharacter == inputCharacters["u"] then
previewHigherScaleNoteAction(7)
end
--
if inputCharacter == inputCharacters["a"] then
previewScaleNoteAction(1)
end
if inputCharacter == inputCharacters["s"] then
previewScaleNoteAction(2)
end
if inputCharacter == inputCharacters["d"] then
previewScaleNoteAction(3)
end
if inputCharacter == inputCharacters["f"] then
previewScaleNoteAction(4)
end
if inputCharacter == inputCharacters["g"] then
previewScaleNoteAction(5)
end
if inputCharacter == inputCharacters["h"] then
previewScaleNoteAction(6)
end
if inputCharacter == inputCharacters["j"] then
previewScaleNoteAction(7)
end
--
if inputCharacter == inputCharacters["z"] then
previewLowerScaleNoteAction(1)
end
if inputCharacter == inputCharacters["x"] then
previewLowerScaleNoteAction(2)
end
if inputCharacter == inputCharacters["c"] then
previewLowerScaleNoteAction(3)
end
if inputCharacter == inputCharacters["v"] then
previewLowerScaleNoteAction(4)
end
if inputCharacter == inputCharacters["b"] then
previewLowerScaleNoteAction(5)
end
if inputCharacter == inputCharacters["n"] then
previewLowerScaleNoteAction(6)
end
if inputCharacter == inputCharacters["m"] then
previewLowerScaleNoteAction(7)
end
--
if inputCharacter == inputCharacters["Q"] then
higherScaleNoteAction(1)
end
if inputCharacter == inputCharacters["W"] then
higherScaleNoteAction(2)
end
if inputCharacter == inputCharacters["E"] then
higherScaleNoteAction(3)
end
if inputCharacter == inputCharacters["R"] then
higherScaleNoteAction(4)
end
if inputCharacter == inputCharacters["T"] then
higherScaleNoteAction(5)
end
if inputCharacter == inputCharacters["Y"] then
higherScaleNoteAction(6)
end
if inputCharacter == inputCharacters["U"] then
higherScaleNoteAction(7)
end
--
if inputCharacter == inputCharacters["A"] then
scaleNoteAction(1)
end
if inputCharacter == inputCharacters["S"] then
scaleNoteAction(2)
end
if inputCharacter == inputCharacters["D"] then
scaleNoteAction(3)
end
if inputCharacter == inputCharacters["F"] then
scaleNoteAction(4)
end
if inputCharacter == inputCharacters["G"] then
scaleNoteAction(5)
end
if inputCharacter == inputCharacters["H"] then
scaleNoteAction(6)
end
if inputCharacter == inputCharacters["J"] then
scaleNoteAction(7)
end
--
if inputCharacter == inputCharacters["Z"] then
lowerScaleNoteAction(1)
end
if inputCharacter == inputCharacters["X"] then
lowerScaleNoteAction(2)
end
if inputCharacter == inputCharacters["C"] then
lowerScaleNoteAction(3)
end
if inputCharacter == inputCharacters["V"] then
lowerScaleNoteAction(4)
end
if inputCharacter == inputCharacters["B"] then
lowerScaleNoteAction(5)
end
if inputCharacter == inputCharacters["N"] then
lowerScaleNoteAction(6)
end
if inputCharacter == inputCharacters["M"] then
lowerScaleNoteAction(7)
end
-----------------
--[[
local function shiftKeyIsHeldDown()
return gfx.mouse_cap & 8 == 8
end
]]--
local function controlKeyIsHeldDown()
return gfx.mouse_cap & 32 == 32
end
local function optionKeyIsHeldDown()
return gfx.mouse_cap & 16 == 16
end
local function commandKeyIsHeldDown()
return gfx.mouse_cap & 4 == 4
end
--
--[[
local function shiftKeyIsNotHeldDown()
return gfx.mouse_cap & 8 ~= 8
end
]]--
local function controlKeyIsNotHeldDown()
return gfx.mouse_cap & 32 ~= 32
end
local function optionKeyIsNotHeldDown()
return gfx.mouse_cap & 16 ~= 16
end
local function commandKeyIsNotHeldDown()
return gfx.mouse_cap & 4 ~= 4
end
--
--[[
local function shiftModifierIsActive()
return shiftKeyIsHeldDown() and controlKeyIsNotHeldDown() and optionKeyIsNotHeldDown() and commandKeyIsNotHeldDown()
end
]]--
local function controlModifierIsActive()
return controlKeyIsHeldDown() and optionKeyIsNotHeldDown() and commandKeyIsNotHeldDown()
end
local function optionModifierIsActive()
return optionKeyIsHeldDown() and controlKeyIsNotHeldDown() and commandKeyIsNotHeldDown()
end
local function commandModifierIsActive()
return commandKeyIsHeldDown() and optionKeyIsNotHeldDown() and controlKeyIsNotHeldDown()
end
---
if inputCharacter == inputCharacters[","] and controlModifierIsActive() then
decrementScaleTonicNoteAction()
end
if inputCharacter == inputCharacters["."] and controlModifierIsActive() then
incrementScaleTonicNoteAction()
end
if inputCharacter == inputCharacters["<"] and controlModifierIsActive() then
decrementScaleTypeAction()
end
if inputCharacter == inputCharacters[">"] and controlModifierIsActive() then
incrementScaleTypeAction()
end
if inputCharacter == inputCharacters[","] and optionModifierIsActive() then
halveGridSize()
end
if inputCharacter == inputCharacters["."] and optionModifierIsActive() then
doubleGridSize()
end
if inputCharacter == inputCharacters["<"] and optionModifierIsActive() then
decrementOctaveAction()
end
if inputCharacter == inputCharacters[">"] and optionModifierIsActive() then
incrementOctaveAction()
end
if inputCharacter == inputCharacters[","] and commandModifierIsActive() then
decrementChordTypeAction()
end
if inputCharacter == inputCharacters["."] and commandModifierIsActive() then
incrementChordTypeAction()
end
if inputCharacter == inputCharacters["<"] and commandModifierIsActive() then
decrementChordInversionAction()
end
if inputCharacter == inputCharacters[">"] and commandModifierIsActive() then
incrementChordInversionAction()
end
end
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
Interface = {}
Interface.__index = Interface
local interfaceWidth = 775
local interfaceHeight = 620
local function getInterfaceXPos()
local screenWidth = getScreenWidth()
return screenWidth/2 - interfaceWidth/2
end
local function getInterfaceYPos()
local screenHeight = getScreenHeight()
return screenHeight/2 - interfaceHeight/2
end
local dockerXPadding = 0
local dockerYPadding = 0
function Interface:init(name)
local self = {}
setmetatable(self, Interface)
self.name = name
self.x = getInterfaceXPos()
self.y = getInterfaceYPos()
self.width = interfaceWidth
self.height = interfaceHeight
self.elements = {}
return self
end
function Interface:restartGui()
self.elements = {}
self:startGui()
end
local function getDockerXPadding()
if gfx.w <= interfaceWidth then
return 0
end
return (gfx.w - interfaceWidth) / 2
end
function Interface:startGui()
currentWidth = gfx.w
dockerXPadding = getDockerXPadding()
self:addMainWindow()
self:addDocker()
self:addTopFrame()
self:addBottomFrame()
end
function Interface:addMainWindow()
gfx.clear = reaper.ColorToNative(36, 36, 36)
local dockState = 0
if windowShouldBeDocked() then
dockState = getDockState()
end
gfx.init(self.name, self.width, self.height, dockState, self.x, self.y)
end
function Interface:addDocker()
local docker = Docker:new()
table.insert(self.elements, docker)
end
function Interface:addChordButton(buttonText, x, y, width, height, scaleNoteIndex, chordTypeIndex, chordIsInScale)
local chordButton = ChordButton:new(buttonText, x, y, width, height, scaleNoteIndex, chordTypeIndex, chordIsInScale)
table.insert(self.elements, chordButton)
end
function Interface:addHeader(headerText, x, y, width, height, getTextCallback)
local header = Header:new(headerText, x, y, width, height, getTextCallback)
table.insert(self.elements, header)
end
function Interface:addFrame(x, y, width, height)
local frame = Frame:new(x, y, width, height)
table.insert(self.elements, frame)
end
function Interface:addLabel(x, y, width, height, getTextCallback)
local label = Label:new(x, y, width, height, getTextCallback)
table.insert(self.elements, label)
end
function Interface:addDropdown(x, y, width, height, options, defaultOptionIndex, onSelectionCallback)
local dropdown = Dropdown:new(x, y, width, height, options, defaultOptionIndex, onSelectionCallback)
table.insert(self.elements, dropdown)
end
function Interface:addChordInversionValueBox(x, y, width, height)
local valueBox = ChordInversionValueBox:new(x, y, width, height)
table.insert(self.elements, valueBox)
end
function Interface:addOctaveValueBox(x, y, width, height)
local valueBox = OctaveValueBox:new(x, y, width, height)
table.insert(self.elements, valueBox)
end
function Interface:updateElements()
for _, element in pairs(self.elements) do
element:update()
end
end
function Interface:update()
self:updateElements()
gfx.update()
if not mouseButtonIsNotPressedDown and leftMouseButtonIsNotHeldDown() then
mouseButtonIsNotPressedDown = true
end
if scaleTonicNote ~= getScaleTonicNote() then
scaleTonicNote = getScaleTonicNote()
updateScaleData()
self:restartGui()
end
if scaleType ~= getScaleType() then
scaleType = getScaleType()
updateScaleData()
self:restartGui()
end
if currentWidth ~= gfx.w then
self:restartGui()
end
if guiShouldBeUpdated then
self:restartGui()
guiShouldBeUpdated = false
end
if windowIsDocked() and (getDockState() ~= gfx.dock(-1)) then
setDockState(gfx.dock(-1))
end
end
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
local windowWidth = 775
scaleNames = {}
for key, scale in ipairs(scales) do
table.insert(scaleNames, scale['name'])
end
local xMargin = 8
local yMargin = 8
local xPadding = 16
local yPadding = 5
local scaleLabelWidth = nil
local horizontalMargin = 8
local scaleTonicNoteWidth = 50
local scaleTypeWidth = 150
local octaveLabelWidth = nil
local octaveValueBoxWidth = 55
keySelectionFrameHeight = 25
function Interface:addTopFrame()
self:addFrame(xMargin+dockerXPadding, yMargin, self.width - 2 * xMargin, keySelectionFrameHeight)
self:addScaleLabel()
self:addScaleTonicNoteDropdown()
self:addScaleTypeDropdown()
self:addScaleNotesTextLabel()
self:addOctaveLabel()
self:addOctaveSelectorValueBox()
end
function Interface:addScaleLabel()
local labelText = "Scale:"
scaleLabelWidth = gfx.measurestr(labelText)
local labelXpos = xMargin+xPadding
local labelYpos = yMargin+yPadding
local labelHeight = 16
self:addLabel(labelXpos+dockerXPadding, labelYpos, scaleLabelWidth, labelHeight, function() return labelText end)
end
function Interface:addScaleTonicNoteDropdown()
local scaleTonicNoteXpos = xMargin+xPadding+scaleLabelWidth+horizontalMargin
local scaleTonicNoteYpos = yMargin+yPadding+1
local scaleTonicNoteHeight = 15
local onScaleTonicNoteSelection = function(i)
setScaleTonicNote(i)
setSelectedScaleNote(1)
setChordText("")
resetSelectedChordTypes()
resetChordInversionStates()
updateScaleData()
updateScaleDegreeHeaders()
end
local scaleTonicNote = getScaleTonicNote()
self:addDropdown(scaleTonicNoteXpos+dockerXPadding, scaleTonicNoteYpos, scaleTonicNoteWidth, scaleTonicNoteHeight, notes, scaleTonicNote, onScaleTonicNoteSelection)
end
function Interface:addScaleTypeDropdown()
local scaleTypeXpos = xMargin+xPadding+scaleLabelWidth+scaleTonicNoteWidth+horizontalMargin*1.5
local scaleTypeYpos = yMargin+yPadding+1
local scaleTypeHeight = 15
local onScaleTypeSelection = function(i)
setScaleType(i)
setSelectedScaleNote(1)
setChordText("")
resetSelectedChordTypes()
resetChordInversionStates()
updateScaleData()
updateScaleDegreeHeaders()
end
local scaleName = getScaleType()
self:addDropdown(scaleTypeXpos+dockerXPadding, scaleTypeYpos, scaleTypeWidth, scaleTypeHeight, scaleNames, scaleName, onScaleTypeSelection)
end
function Interface:addScaleNotesTextLabel()
local getScaleNotesTextCallback = function() return getScaleNotesText() end
local scaleNotesXpos = xMargin+xPadding+scaleLabelWidth+scaleTonicNoteWidth+scaleTypeWidth+horizontalMargin*2+4
local scaleNotesYpos = yMargin+yPadding+1
local scaleNotesWidth = 360
local scaleNotesHeight = 15
self:addLabel(scaleNotesXpos+dockerXPadding, scaleNotesYpos, scaleNotesWidth, scaleNotesHeight, getScaleNotesTextCallback)
end
function Interface:addOctaveLabel()
local labelText = "Octave:"
octaveLabelWidth = gfx.measurestr(labelText)
local labelYpos = yMargin+yPadding+1
local labelHeight = 15
local labelXpos = windowWidth - 80 - octaveValueBoxWidth
self:addLabel(labelXpos+dockerXPadding, labelYpos, octaveLabelWidth, labelHeight, function() return labelText end)
end
function Interface:addOctaveSelectorValueBox()
local windowWidth = 775
local valueBoxXPos = windowWidth - octaveValueBoxWidth - xMargin - xPadding + 3
local valueBoxYPos = yMargin + 6
local valueBoxHeight = 15
self:addOctaveValueBox(valueBoxXPos+dockerXPadding, valueBoxYPos, octaveValueBoxWidth, valueBoxHeight)
end
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
local xMargin = 8
local yMargin = 8 + keySelectionFrameHeight + 6
local xPadding = 7
local yPadding = 30
local headerHeight = 25
local inversionLabelWidth = 80
local inversionValueBoxWidth = 55
local chordTextWidth = nil
function Interface:addBottomFrame()
local chordButtonsFrameHeight = self.height - yMargin - 6
self:addFrame(xMargin+dockerXPadding, yMargin, self.width - 2 * xMargin, chordButtonsFrameHeight)
self:addChordTextLabel()
self:addInversionLabel()
self:addInversionValueBox()
self:addHeaders()
self:addChordButtons()
end
function Interface:addChordTextLabel()
local getChordTextCallback = function() return getChordText() end
local chordTextXpos = xMargin + xPadding
local chordTextYpos = yMargin + 4
chordTextWidth = self.width - 4 * xMargin - inversionLabelWidth - inversionValueBoxWidth - 6
local chordTextHeight = 24
self:addLabel(chordTextXpos+dockerXPadding, chordTextYpos, chordTextWidth, chordTextHeight, getChordTextCallback)
end
function Interface:addInversionLabel()
local inversionLabelText = "Inversion:"
local inversionLabelXPos = xMargin + xPadding + chordTextWidth
local inversionLabelYPos = yMargin + 4
local stringWidth, _ = gfx.measurestr(labelText)
local inversionLabelTextHeight = 24
self:addLabel(inversionLabelXPos+dockerXPadding, inversionLabelYPos, inversionLabelWidth, inversionLabelTextHeight, function() return inversionLabelText end)
end
function Interface:addInversionValueBox()
local inversionValueBoxXPos = xMargin + xPadding + chordTextWidth + inversionLabelWidth + 2
local inversionValueBoxYPos = yMargin + 9
local inversionValueBoxHeight = 15
self:addChordInversionValueBox(inversionValueBoxXPos+dockerXPadding, inversionValueBoxYPos, inversionValueBoxWidth, inversionValueBoxHeight)
end
function Interface:addHeaders()
for i = 1, #scaleNotes do
local headerWidth = 104
local innerSpacing = 2
local headerXpos = xMargin+xPadding-1 + headerWidth * (i-1) + innerSpacing * i
local headerYpos = yMargin+yPadding
self:addHeader(headerXpos+dockerXPadding, headerYpos, headerWidth, headerHeight, function() return getScaleDegreeHeader(i) end)
end
end
function Interface:addChordButtons()
local scaleNoteIndex = 1
for note = getScaleTonicNote(), getScaleTonicNote() + 11 do
if noteIsInScale(note) then
for chordTypeIndex, chord in ipairs(scaleChords[scaleNoteIndex]) do
local text = getScaleNoteName(scaleNoteIndex) .. chord['display']
local buttonWidth = 104
local buttonHeight = 38
local innerSpacing = 2
local xPos = xMargin + xPadding + buttonWidth * (scaleNoteIndex-1) + innerSpacing * scaleNoteIndex + dockerXPadding
local yPos = yMargin + yPadding + headerHeight + buttonHeight * (chordTypeIndex-1) + innerSpacing * (chordTypeIndex-1) - 3
local numberOfChordsInScale = getNumberOfScaleChordsForScaleNoteIndex(scaleNoteIndex)
if chordTypeIndex > numberOfChordsInScale then
local chordIsInScale = false
self:addChordButton(text, xPos, yPos, buttonWidth, buttonHeight, scaleNoteIndex, chordTypeIndex, chordIsInScale)
else
local chordIsInScale = true
self:addChordButton(text, xPos, yPos, buttonWidth, buttonHeight, scaleNoteIndex, chordTypeIndex, chordIsInScale)
end
end
scaleNoteIndex = scaleNoteIndex + 1
end
end
end
local workingDirectory = reaper.GetResourcePath() .. "/Scripts/ChordGun/src"
--clearConsoleWindow()
updateScaleData()
local interface = Interface:init("ChordGun")
interface:startGui()
local function windowHasNotBeenClosed()
return inputCharacter ~= -1
end
local function main()
handleInput()
if windowHasNotBeenClosed() then
reaper.runloop(main)
end
interface:update()
end
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment