diff --git a/MIDI Editor/talagan_OneSmallStep.lua b/MIDI Editor/talagan_OneSmallStep.lua index a4e5f2b8a..ae268f48d 100644 --- a/MIDI Editor/talagan_OneSmallStep.lua +++ b/MIDI Editor/talagan_OneSmallStep.lua @@ -1,6 +1,6 @@ --[[ @description One Small Step : Alternative Step Input -@version 0.9.5 +@version 0.9.6 @author Ben 'Talagan' Babut @license MIT @metapackage @@ -24,13 +24,19 @@ [main=main,midi_editor] talagan_OneSmallStep/actions/talagan_OneSmallStep Change note len.lua > talagan_OneSmallStep/actions/talagan_OneSmallStep Change note len - 1_4.lua [main=main,midi_editor] talagan_OneSmallStep/actions/talagan_OneSmallStep Change note len.lua > talagan_OneSmallStep/actions/talagan_OneSmallStep Change note len - 1_2.lua [main=main,midi_editor] talagan_OneSmallStep/actions/talagan_OneSmallStep Change note len.lua > talagan_OneSmallStep/actions/talagan_OneSmallStep Change note len - 1.lua + [main=main,midi_editor] talagan_OneSmallStep/actions/talagan_OneSmallStep Edit Action.lua > talagan_OneSmallStep/actions/talagan_OneSmallStep Edit Action - Commit.lua + [main=main,midi_editor] talagan_OneSmallStep/actions/talagan_OneSmallStep Edit Action.lua > talagan_OneSmallStep/actions/talagan_OneSmallStep Edit Action - CommitBack.lua + [main=main,midi_editor] talagan_OneSmallStep/actions/talagan_OneSmallStep Edit Action.lua > talagan_OneSmallStep/actions/talagan_OneSmallStep Edit Action - Insert.lua + [main=main,midi_editor] talagan_OneSmallStep/actions/talagan_OneSmallStep Edit Action.lua > talagan_OneSmallStep/actions/talagan_OneSmallStep Edit Action - InsertBack.lua + [main=main,midi_editor] talagan_OneSmallStep/actions/talagan_OneSmallStep Edit Action.lua > talagan_OneSmallStep/actions/talagan_OneSmallStep Edit Action - Write.lua + [main=main,midi_editor] talagan_OneSmallStep/actions/talagan_OneSmallStep Edit Action.lua > talagan_OneSmallStep/actions/talagan_OneSmallStep Edit Action - WriteBack.lua + [main=main,midi_editor] talagan_OneSmallStep/actions/talagan_OneSmallStep Edit Action.lua > talagan_OneSmallStep/actions/talagan_OneSmallStep Edit Action - Replace.lua + [main=main,midi_editor] talagan_OneSmallStep/actions/talagan_OneSmallStep Edit Action.lua > talagan_OneSmallStep/actions/talagan_OneSmallStep Edit Action - ReplaceBack.lua + [main=main,midi_editor] talagan_OneSmallStep/actions/talagan_OneSmallStep Edit Action.lua > talagan_OneSmallStep/actions/talagan_OneSmallStep Edit Action - Navigate.lua + [main=main,midi_editor] talagan_OneSmallStep/actions/talagan_OneSmallStep Edit Action.lua > talagan_OneSmallStep/actions/talagan_OneSmallStep Edit Action - NavigateBack.lua [main=main,midi_editor] talagan_OneSmallStep/actions/talagan_OneSmallStep Increase note len.lua [main=main,midi_editor] talagan_OneSmallStep/actions/talagan_OneSmallStep Decrease note len.lua [main=main,midi_editor] talagan_OneSmallStep/actions/talagan_OneSmallStep Cleanup helper JSFXs.lua - [main=main,midi_editor] talagan_OneSmallStep/actions/talagan_OneSmallStep Commit back.lua - [main=main,midi_editor] talagan_OneSmallStep/actions/talagan_OneSmallStep Commit.lua - [main=main,midi_editor] talagan_OneSmallStep/actions/talagan_OneSmallStep Insert Commit back.lua - [main=main,midi_editor] talagan_OneSmallStep/actions/talagan_OneSmallStep Insert Commit.lua [main=main,midi_editor] talagan_OneSmallStep/actions/talagan_OneSmallStep Set or remove playback marker.lua [main=main,midi_editor] talagan_OneSmallStep/actions/talagan_OneSmallStep Playback.lua [nomain] talagan_OneSmallStep/classes/*.lua @@ -41,116 +47,43 @@ @screenshot https://stash.reaper.fm/48269/oss_094.png @changelog - - [Feature] Added insert/cursor mode (inserts + move things forward, deletes backwards) - - [Feature] Added pedal repeater - - [UI] Aded status icons for modifier modes/keys (insert / backward / insert+backward) - - [Rework] Changed folder structure + - [Feature] Added Replace mode + - [Feature] Added Navigate mode + - [Feature] Added auto-scroll arrange view option + - [Feature] [All Input Modes] Handle grid size for note length with modifier factor + - [Feature] [All Input Modes] Handle swing for grid size note length + - [Feature] [Navigate] Snap on project grid (with swing) + - [Feature] [Navigate] Snap on item grid (with swing) + - [Feature] [Navigate] Snap on note start/ends + - [Feature] [Navigate] Snap on item bounds + - [Feature] [Navigate] Added option to allow navigation on key events (does not input notes) + - [Feature] [Write] Step back delete/shortening now happens on every key press/release event (notes should match keys) + - [Feature] [Write] Added option to prevent the cursor from being moved back if step back delete fails (notes don't match keys, the user missed) + - [Feature] [Insert] Step back delete can now make holes + - [Feature] Added system to engage modes with buttons or with customizable modifiers + - [Rework] [Write] Reworked Delete/Step back logic + - [Rework] [Insert] Reworked Delete/Step back logic + - [Rework] Removed option "do not add notes if step back modifier key is pressed", not pertinent anymore + - [Rework] Removed option "erase note ends even if they do not align on cursor", since the eraser does more complex things, it does not fit in the new flow + - [Bug Fix] n-tuplets always used a value of 2/n, now using precpow2(n)/n + - [Bug Fix] Create new items when advancing only if insert mode is on + - [Bug fix] Icons/Images coould be randomly wrong @about # Purpose - One Small Step is a tool for performing MIDI note step input in REAPER. It is an alternative to the standard step input, and it tries to address some issues with certain workflows, as well as to propose different input modes, like validating held notes with the sustain pedal or a REAPER action (obviously linked to a custom keyboard shortcut). It will also work outside of the MIDI editor (in the arrange view), as long as you've selected a MIDI item and set the cursor at the right position ; this offers additional comfort and can speed up your workflow. - - # On MIDI issues with Reaper's standard step input flow - - REAPER's step input tool uses the MIDI control path. While it has some advantages, one of the main issue you may have encountered is that when step inputing, MIDI events will not go through the input FX chain of the track you're working on. If you are performing MIDI processing there (like channel routing, note transposition, note dropping, velocity processing, etc), everything will be ignored because REAPER does not use the result of the FX input chain, but the raw MIDI note events. This leads to strange behaviours, e.g. the MIDI editor piano roll not being in coherency with the input notes (so what you see on the piano roll is not what you'll get), but worse, you will not get the same result as if you were recording. - - To address this, One Small Step installs a JSFX at the end of the track input chain to watch for note events AFTER they've been processed by the FX input chain, and performs the patching of the MIDI item by itself. - - # Reaper forum thread - - The official discussion thread is located here : https://forum.cockos.com/showthread.php?t=288076 + One Small Step is a tool for performing MIDI note step input in REAPER. It is an alternative to the standard step input, offering more control and tools, and making allowing the use of the sustain pedal (+ keyboard modifier keys) for validating things. It offers multiple input modes, based on keyboard press/release events, or with strict pedal/action validation. It allows inputing, inserting, erasing, translating notes with minimal use of the mouse. . It will work outside of the MIDI editor (directly in the arrange view), as long as you've selected a MIDI item and set the cursor at the right position ; this offers additional comfort and can speed up your workflow. It also addresses some issues with workflows that use the input FX chain for routing/transposing MIDI (because Reaper's standard input bypasses the fx input chain). # Install Notes This script also needs the JS_ReaScriptAPI api by Julian Sader and the ReaImGui library by Christian Fillion to work. Please install them alongside (OSS will remind you to do so anyway). A restart of Reaper is needed after install. - # How to use - - Launch the action called 'OneSmallStep' (other actions are provided but we'll get on this later). You should now see OSS's main dialog - One Small Step is active (it is active as long as this dialog is visible). At the top of it, the name of the target MIDI track / item / take will be displayed if there's one eligible that matches your current selection / cursor position. - - It is important to note that the track should be armed for record (OSS will give you an indication if you forgot to arm the recording) and the MIDI source should be chosen (exactly like you would when recording). If everyhing's ready, a red circle will glow, meaning that in this configuration, OneSmallStep is able to do its job (listen to MIDI events, and step input/patch the current MIDI item). - - ## Input modes - - You can then select your input mode between **Keyboard Press** Mode, **Punch** Mode, and **Keyboard Release** Mode. - - For each Input Mode, two triggers may be used to validate notes and rests : the Commit action, and the Commit Back action, to which you may consider giving shortcuts. The effect of each action will be different if the notes were already held or not (creation, extension, shortening, removal ...). Those two actions may also be triggered by the Sustain Pedal (for the Commit) or a modifier key (shift, ctrl, etc) + Sustain Pedal (for the Commit Back action). - - ### Keyboard Press Mode (Fast Mode) - - Notes are added on keyboard key press events. - - Suitable for inputing notes at a high pace. It is not error tolerant (you get what you play), but will only aggregate chords if keys are pressed simultaneously. - - ### Punch Mode - - Notes are NOT added on keyboard key press/release events. Only the sustain pedal or commit action add notes. - - Suitable for validating everything by ear before input. Useful when testing chords or melodic ideas. - - ### Keyboard Release Mode (Grope Mode) - - Notes are added on keyboard key release events. - - Suitable for inputing notes at a low pace, correcting things by ear, especially for chords. This mode is error tolerant, but tends to aggregate and skip notes easily when playing fast. - - This is pretty much the same as Reaper's default step input mode. - - ### Effect of the sustain pedal / actions - - For all modes, the sustain pedal and the commit action : - - - Insert held notes - - Extend already committed and still held notes - - Insert rests if no notes are held - - The modifier key + the sustain pedal and the commit back action : - - - Erase back held notes if they match the cursor - - Step back if no notes are held - - ## Note length parameter source - - Three sources for determining the input note length are proposed. - - ### One Small Step - - Note length parameters are global and configured in OSS, with the buttons aside. - - ### Project Grid - - One Small Step will use the grid parameters of the project to determine the length of the notes to insert - - ### MIDI Item's conf - - One Small Step will use the note parameters specific to the edited MIDI item to determine the length of the notes to insert. Those parameters are located at the bottom of the MIDI Editor (the combo boxes right of the 'Notes' label). - - ## Step input playback - - One Small Step provides a convenient playback widget, which is a way to ear what you've just written, without losing the position of the edit cursor, so that you can work faster. The playback button will replay the last N measures (N is settable, and the result is rounded to the start of the matching measure). You can chose Mk instead of a number of measures, and instead, the start point will be the 'OSS Playback' marker (if it is set, else, only the current measure will be played as when N=0). You can set/remove it using the marker button on the right. - - Both the "set/move/remove marker" and "playback" actions are available independently so you can also use them without the UI if you need them in other workflows. - - ## Other Reaper actions - - To speed up your flow, multiple actions are provided to quickly change OSS parameters, so that you can assign shortcuts to them. Those are : - - - **Change input mode** - - **Change note len** - - **Decrease/Increase note len** - - **Change note len modifier** - - **Change note len param source** - - **Cleanup helper JSFXs** - - actions, whose names should be self explanatory. The **Cleanup helper JSFXs** is here for cleaniness, to remove the Helper JSFXs that are installed automatically on the input FX chain of your tracks when OSS is running (it could have been done automatically when closing the tool, but it adds an entry in the undo stack, which is annoying, and I don't have a solution for this yet). - - # Calling One Small Step from a Reaper toolbar button + # Reaper forum thread - The most logical way to summon OSS is to create a togglable toolbar button in Reaper by assigning it the 'talagan_OneSmallStep.lua' action. You should be good to go : OSS will handle the color of the button dependending on its state, and you can close OSS either by clicking on the cross in the top right corner of the window, or by re-clicking the toolbar button. + The official discussion thread is located here : https://forum.cockos.com/showthread.php?t=288076 - # Toolbar icons + # Documentation - Two toolbar icons are provided with OSS, one icon for launching OSS ('toolbar_one_small_step'), and one for launching the cleanup script ('toolbar_one_small_step_cleanup'). + Since the documentation is growing, it is now centralized on the forum thread. # Credits @@ -212,20 +145,21 @@ dofile(reaper.GetResourcePath() .. '/Scripts/ReaTeam Extensions/API/imgui.lua')( ------------------------------- +local ctx = reaper.ImGui_CreateContext('One Small Step'); + +------------------------------- + local images = {}; function getImage(image_name) - if not reaper.ImGui_ValidatePtr(images[image_name], 'ImGui_Image*') then - local bin = require("./talagan_OneSmallStep/images/" .. image_name); - images[image_name] = reaper.ImGui_CreateImageFromMem(bin); + if (not images[image_name]) or (not reaper.ImGui_ValidatePtr(images[image_name], 'ImGui_Image*')) then + local bin = require("./talagan_OneSmallStep/images/" .. image_name) + images[image_name] = reaper.ImGui_CreateImageFromMem(bin) + -- Prevent the GC from freeing this image + reaper.ImGui_Attach(ctx, images[image_name]) end - return images[image_name]; + return images[image_name] end - -------------------------------- - -local ctx = reaper.ImGui_CreateContext('One Small Step'); - ------------------------------- -- Other global variables @@ -238,6 +172,10 @@ function SL() reaper.ImGui_SameLine(ctx); end +function XSeparator() + reaper.ImGui_SetCursorPosY(ctx, reaper.ImGui_GetCursorPosY(ctx) + 2) ; reaper.ImGui_Text(ctx, "x "); +end + function TT(str) if reaper.ImGui_IsItemHovered(ctx, reaper.ImGui_HoveredFlags_DelayNormal()) then reaper.ImGui_SetTooltip(ctx, str) @@ -296,7 +234,7 @@ local KnownNoteLengthSignatures = { ['3/256'] = { icon = "note_1", triplet = false, modif_label = ". x 1/128" }, } -function ImGui_QNToLabel(ctx, qn) +function QNToLabel(ctx, qn, swing) local n,d,e = to_frac(qn); @@ -310,24 +248,33 @@ function ImGui_QNToLabel(ctx, qn) else ImGui_NoteLenImg(ctx, "note_1", false, "x "..sig); end + + if swing ~= 0 then + SL() + reaper.ImGui_SetCursorPosY(ctx, reaper.ImGui_GetCursorPosY(ctx) + 2) + reaper.ImGui_Text(ctx, "(sw) ") + end end -- Indicator for the current project grid note len -function ImGui_ProjectGridLabel(ctx) - local _, qn, swing, _ = reaper.GetSetProjectGrid(0, false); +function ProjectGridLabel(ctx) + local _, qn, swingmode, swing = reaper.GetSetProjectGrid(0, false) + if swingmode ~= 1 then + swing = 0 + end - reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_ItemSpacing(),0, 0); + reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_ItemSpacing(), 0, 0); if swing == 3 then reaper.ImGui_TextColored(ctx, 0xC0C0C0FF, "Measure"); else - ImGui_QNToLabel(ctx, qn); + QNToLabel(ctx, qn, swing) end - reaper.ImGui_PopStyleVar(ctx,1); + reaper.ImGui_PopStyleVar(ctx,1) end -- Indicator for the current MIDI item note len -function ImGui_ItemGridLabel(ctx,take) +function ItemGridLabel(ctx,take) if not take then return end @@ -341,68 +288,79 @@ function ImGui_ItemGridLabel(ctx,take) local qn = note_len/4; reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_ItemSpacing(),0, 0); - ImGui_QNToLabel(ctx, qn); + QNToLabel(ctx, qn, swing); reaper.ImGui_PopStyleVar(ctx,1); end -function ButtonGroupImageButton(image_name, is_on, callback, corner, is_green) - reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_FramePadding(), 0, 0); +local ColorSets = { + Blue = { + on = 0x5080FFFF, + off = 0x203040FF, + hover = 0x3070BBFF, + active = 0x60A0FFFF, + onover = 0xFFFFFFFF, + offover = 0xFFFFFFFF + }, + Green = { + on = 0x008000FF, + off = 0x006000FF, + hover = 0x00C000FF, + active = 0x00C000FF, + onover = 0xFFFFFFFF, + offover = 0xFFFFFFFF + }, + Snap = { + on = 0x00000000, + off = 0x00000000, + hover = 0x203040FF, + active = 0xFFE03cFF, + onover = 0xFFE03cFF, + offover = 0x808080FF + } +} - if is_green then - PushGreenButtonColors(is_on); - else - PushBlueButtonColors(is_on); - end +function PushButtonColors(colorset, is_on) + local cs = ColorSets[colorset] - if corner == nil then - corner = 0.1 - end + reaper.ImGui_PushStyleColor(ctx, reaper.ImGui_Col_Button(), is_on and cs.on or cs.off); + reaper.ImGui_PushStyleColor(ctx, reaper.ImGui_Col_ButtonHovered(), cs.hover ); + reaper.ImGui_PushStyleColor(ctx, reaper.ImGui_Col_ButtonActive(), cs.active ); +end - if reaper.ImGui_ImageButton(ctx, image_name, getImage(image_name), 20, 20, corner, corner, 1 - corner, 1 - corner, 0, 0xFFFFFFFF) then - callback(); - end +function PopButtonColors() + reaper.ImGui_PopStyleColor(ctx, 3) +end - if is_green then - PopGreenButtonColors(); - else - PopBlueButtonColors(); - end +function ButtonGroupImageButton(image_name, is_on, options) - reaper.ImGui_PopStyleVar(ctx,1); -end + options = options or {} -function PushBlueButtonColors(is_on) - local on_col = 0x5080FFFF; - local off_col = 0x203040FF; - local hov_col = 0x60A0FFFF; - local act_col = 0x60A0FFFF; + local colorset = options['colorset'] or "Blue" + local corner = options['corner'] or 0 + local cs = ColorSets[colorset] - reaper.ImGui_PushStyleColor(ctx, reaper.ImGui_Col_Button(), is_on and on_col or off_col); - reaper.ImGui_PushStyleColor(ctx, reaper.ImGui_Col_ButtonHovered(),hov_col ); - reaper.ImGui_PushStyleColor(ctx, reaper.ImGui_Col_ButtonActive(), act_col ); -end + reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_FramePadding(), 0, 0); -function PopBlueButtonColors() - reaper.ImGui_PopStyleColor(ctx,3); -end + PushButtonColors(colorset, is_on); -function PushGreenButtonColors(is_on) + reaper.ImGui_IsItemHovered(ctx); - local on_col = 0x008000FF; - local off_col = 0x006000FF; - local hov_col = 0x00C000FF; - local act_col = 0x00C000FF; + local ret = reaper.ImGui_ImageButton(ctx, image_name, getImage(image_name), + 20, 20, + corner, corner, + 1 - corner, 1 - corner, + 0, (is_on) and (cs.onover) or (cs.offover)) - reaper.ImGui_PushStyleColor(ctx, reaper.ImGui_Col_Button(), is_on and on_col or off_col); - reaper.ImGui_PushStyleColor(ctx, reaper.ImGui_Col_ButtonHovered(),hov_col ); - reaper.ImGui_PushStyleColor(ctx, reaper.ImGui_Col_ButtonActive(), act_col ); -end + PopButtonColors() + + reaper.ImGui_PopStyleVar(ctx,1); -function PopGreenButtonColors() - reaper.ImGui_PopStyleColor(ctx,3); + return ret end + + function ButtonGroupTextButton(text, is_on, callback) if reaper.ImGui_Button(ctx, text) then @@ -419,13 +377,16 @@ function ImGui_NoteLenImg(context, image_name, triplet, divider) SL(); reaper.ImGui_SetCursorPosX(ctx, reaper.ImGui_GetCursorPosX(ctx) - 20); reaper.ImGui_SetCursorPosY(ctx, reaper.ImGui_GetCursorPosY(ctx) - 10); - ImGui_NoteLenImg(ctx, "note_triplet"); + ImGui_NoteLenImg(ctx, "note_triplet") end - if divider then - SL(); + if divider and divider ~= "" then + SL() + if divider:match("^.") then + reaper.ImGui_SetCursorPosX(ctx,reaper.ImGui_GetCursorPosX(ctx) - 2); + end reaper.ImGui_SetCursorPosY(ctx,reaper.ImGui_GetCursorPosY(ctx) + 3); - reaper.ImGui_TextColored(ctx, 0xC0C0C0FF, divider); + reaper.ImGui_TextColored(ctx, 0xC0C0C0FF, divider .. " ") end end @@ -515,12 +476,11 @@ function TrackInfo(track) RecordIssues(track); end - - -- MINIBAR : Input Mode function InputModeMiniBar() local mode = engine_lib.getInputMode(); - local modifkey = engine_lib.getSPStepBackModifierKey().name or ""; + local modifkey = engine_lib.getSetting("StepBackModifierKey") + local mkinfo = engine_lib.ModifierKeyLookup[modifkey]; local pedalmanual = "\z The sustain pedal and the commit action :\n\n\z @@ -528,13 +488,13 @@ function InputModeMiniBar() \32 - Extend already committed and still held notes\n\z \32 - Insert rests if no notes are held\n\z \n\z - " .. modifkey .. " + the sustain pedal and the commit back action :\n\n\z + " .. mkinfo.name .. " + the sustain pedal and the commit back action :\n\n\z \32 - Erase back held notes if they match the cursor\n\z \32 - Step back if no notes are held"; - ButtonGroupImageButton('input_mode_keyboard_press', mode == engine_lib.InputMode.KeyboardPress, function() - engine_lib.setInputMode(engine_lib.InputMode.KeyboardPress); - end, 0); + if ButtonGroupImageButton('input_mode_keyboard_press', mode == engine_lib.InputMode.KeyboardPress) then + engine_lib.setInputMode(engine_lib.InputMode.KeyboardPress); + end TT("Input Mode : Keyboard Press (Fast mode)\n\z \n\z @@ -546,9 +506,9 @@ function InputModeMiniBar() \n\z" .. pedalmanual); SL(); - ButtonGroupImageButton('input_mode_pedal', mode == engine_lib.InputMode.Punch, function() - engine_lib.setInputMode(engine_lib.InputMode.Punch); - end,0); + if ButtonGroupImageButton('input_mode_pedal', mode == engine_lib.InputMode.Punch) then + engine_lib.setInputMode(engine_lib.InputMode.Punch); + end TT("Input Mode : Punch (Check mode)\n\z \n\z @@ -560,9 +520,9 @@ function InputModeMiniBar() \n\z" .. pedalmanual); SL(); - ButtonGroupImageButton('input_mode_keyboard_release', mode == engine_lib.InputMode.KeyboardRelease, function() - engine_lib.setInputMode(engine_lib.InputMode.KeyboardRelease); - end, 0); + if ButtonGroupImageButton('input_mode_keyboard_release', mode == engine_lib.InputMode.KeyboardRelease) then + engine_lib.setInputMode(engine_lib.InputMode.KeyboardRelease) + end TT("Input Mode : Keyboard Release (Grope mode)\n\z \n\z @@ -581,79 +541,87 @@ end function ConfSourceMiniBar() local nlm = engine_lib.getNoteLenParamSource(); - ButtonGroupImageButton('note_len_mode_oss', nlm == engine_lib.NoteLenParamSource.OSS, function() engine_lib.setNoteLenParamSource(engine_lib.NoteLenParamSource.OSS) end, 0); + if ButtonGroupImageButton('note_len_mode_oss', nlm == engine_lib.NoteLenParamSource.OSS) then + engine_lib.setNoteLenParamSource(engine_lib.NoteLenParamSource.OSS) + end TT('Note Length conf : One Small Step\n\nUse the params aside.'); SL(); - ButtonGroupImageButton('note_len_mode_pgrid', nlm == engine_lib.NoteLenParamSource.ProjectGrid, function() engine_lib.setNoteLenParamSource(engine_lib.NoteLenParamSource.ProjectGrid) end); + + if ButtonGroupImageButton('note_len_mode_pgrid', nlm == engine_lib.NoteLenParamSource.ProjectGrid) then + engine_lib.setNoteLenParamSource(engine_lib.NoteLenParamSource.ProjectGrid) + end TT( "Note Length conf : Project\n\nUse the project's grid conf."); SL(); - ButtonGroupImageButton('note_len_mode_igrid', nlm == engine_lib.NoteLenParamSource.ItemConf, function() engine_lib.setNoteLenParamSource(engine_lib.NoteLenParamSource.ItemConf) end); - TT( "Note Length conf : MIDI Item\n\nUse the MIDI item's own conf.\n\n('Notes' at the bottom of the MIDI editor)"); + if ButtonGroupImageButton('note_len_mode_inote', nlm == engine_lib.NoteLenParamSource.ItemConf) then + engine_lib.setNoteLenParamSource(engine_lib.NoteLenParamSource.ItemConf) + end + TT( "Note Length conf : MIDI Item\n\nUse the MIDI item's own conf.\n\n('Notes' at the bottom of the MIDI editor)"); end -- MINIBAR : Note length -function NoteLenMiniBar() +function NoteLenMiniBar(with_fracs) local nl = engine_lib.getNoteLen(); for i,v in ipairs(engine_lib.NoteLenDefs) do - SL(); - ButtonGroupImageButton('note_'.. v.id , nl == v.id, - function() + if i > 1 then + SL() + end + local icon = (with_fracs) and ('frac_' .. v.frac) or ('note_' .. v.id) + if ButtonGroupImageButton(icon, nl == v.id, {corner = (with_fracs and 0 or 0.1)} ) then engine_lib.setNoteLen(v.id) - end - ); + end end end -- MINIBAR : Note length modifier -function NoteLenModifierMiniBar() +function NoteLenModifierMiniBar(with_fracs) local nmod = engine_lib.getNoteLenModifier(); - ButtonGroupImageButton('note_dotted', nmod == engine_lib.NoteLenModifier.Dotted, function() - if nmod == engine_lib.NoteLenModifier.Dotted then - engine_lib.setNoteLenModifier(engine_lib.NoteLenModifier.Straight); - else - engine_lib.setNoteLenModifier(engine_lib.NoteLenModifier.Dotted); - end + if ButtonGroupImageButton(with_fracs and 'frac_3_2' or 'note_dotted', nmod == engine_lib.NoteLenModifier.Dotted, {corner = with_fracs and 0 or 0.1}) then + if nmod == engine_lib.NoteLenModifier.Dotted then + engine_lib.setNoteLenModifier(engine_lib.NoteLenModifier.Straight); + else + engine_lib.setNoteLenModifier(engine_lib.NoteLenModifier.Dotted); end - ); - TT("Dotted"); + end + TT(with_fracs and "3/2" or "Dotted"); SL(); - ButtonGroupImageButton('note_triplet', nmod == engine_lib.NoteLenModifier.Triplet, function() - if nmod == engine_lib.NoteLenModifier.Triplet then - engine_lib.setNoteLenModifier(engine_lib.NoteLenModifier.Straight); - else - engine_lib.setNoteLenModifier(engine_lib.NoteLenModifier.Triplet); - end + + if ButtonGroupImageButton(with_fracs and 'frac_2_3' or 'note_triplet', nmod == engine_lib.NoteLenModifier.Triplet, {corner = with_fracs and 0 or 0.1}) then + if nmod == engine_lib.NoteLenModifier.Triplet then + engine_lib.setNoteLenModifier(engine_lib.NoteLenModifier.Straight); + else + engine_lib.setNoteLenModifier(engine_lib.NoteLenModifier.Triplet); end - ); - TT("Triplet"); + end + TT(with_fracs and "2/3" or "Triplet"); SL(); - ButtonGroupImageButton('note_modified', nmod == engine_lib.NoteLenModifier.Modified, function() - if nmod == engine_lib.NoteLenModifier.Modified then - engine_lib.setNoteLenModifier(engine_lib.NoteLenModifier.Straight); - else - engine_lib.setNoteLenModifier(engine_lib.NoteLenModifier.Modified); - end + + if ButtonGroupImageButton(with_fracs and 'frac_1_n' or 'note_tuplet', nmod == engine_lib.NoteLenModifier.Tuplet, {corner = with_fracs and 0 or 0.1}) then + if nmod == engine_lib.NoteLenModifier.Tuplet then + engine_lib.setNoteLenModifier(engine_lib.NoteLenModifier.Straight); + else + engine_lib.setNoteLenModifier(engine_lib.NoteLenModifier.Tuplet); end - ); - TT("Modified length"); - SL(); - ButtonGroupImageButton('note_tuplet', nmod == engine_lib.NoteLenModifier.Tuplet, function() - if nmod == engine_lib.NoteLenModifier.Tuplet then - engine_lib.setNoteLenModifier(engine_lib.NoteLenModifier.Straight); - else - engine_lib.setNoteLenModifier(engine_lib.NoteLenModifier.Tuplet); - end + end + TT(with_fracs and "1/n" or "N-tuplet"); + SL() + + + if ButtonGroupImageButton('note_modified', nmod == engine_lib.NoteLenModifier.Modified ) then + if nmod == engine_lib.NoteLenModifier.Modified then + engine_lib.setNoteLenModifier(engine_lib.NoteLenModifier.Straight); + else + engine_lib.setNoteLenModifier(engine_lib.NoteLenModifier.Modified); end - ); - TT("N-tuplet"); + end + TT(with_fracs and "n/m" or "Modified length"); end -- Sub-params : N-tuplet function NTupletComboBox() - local combo_items = { '4', '5', '6', '7', '8', '9', '10', '11', '12' } + local combo_items = { '2', '3','4', '5', '6', '7', '8', '9', '10', '11', '12' } reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_FramePadding(), 5, 3.5); reaper.ImGui_SetCursorPosY(ctx, reaper.ImGui_GetCursorPosY(ctx)); @@ -679,47 +647,27 @@ function NTupletComboBox() end -- Sub-params : Augmented/Diminished Sign/Factor -function NoteADSignComboBox() - - local val = engine_lib.getNoteADSign(); - local combo_items = { '+', '-' }; +function NoteLenFactorComboBox(role) -- Numerator/Denominator - reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_FramePadding(), 5, 3.5); - reaper.ImGui_SetCursorPosY(ctx, reaper.ImGui_GetCursorPosY(ctx)); - reaper.ImGui_PushID(ctx, "augmented_diminshed_sign"); + local setting = "NoteLenFactor" .. role + local curval = engine_lib.getSetting(setting) + local combo_items = { } - reaper.ImGui_SetNextItemWidth(ctx, 40); - if reaper.ImGui_BeginCombo(ctx, '', val) then - for i, label in ipairs(combo_items) do - - local is_selected = (val == label); - if reaper.ImGui_Selectable(ctx, label, is_selected) then - engine_lib.setNoteADSign(label); - end - if is_selected then - reaper.ImGui_SetItemDefaultFocus(ctx) - end - end - reaper.ImGui_EndCombo(ctx) + for i = 1, 32 do + combo_items[#combo_items+1] = i end - reaper.ImGui_PopID(ctx); - reaper.ImGui_PopStyleVar(ctx,1); -end - -function NoteADFactorComboBox() - - local val = engine_lib.getNoteADFactor(); reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_FramePadding(), 5, 3.5); reaper.ImGui_SetCursorPosY(ctx, reaper.ImGui_GetCursorPosY(ctx)); - reaper.ImGui_PushID(ctx, "augmented_diminished_combo"); + reaper.ImGui_PushID(ctx, "NoteLenFactor" .. role); - reaper.ImGui_SetNextItemWidth(ctx, 55); - if reaper.ImGui_BeginCombo(ctx, '', val) then - for i, v in ipairs(engine_lib.AugmentedDiminishedDefs) do + reaper.ImGui_SetNextItemWidth(ctx, 45); + if reaper.ImGui_BeginCombo(ctx, '', curval) then + for i, val in ipairs(combo_items) do - if reaper.ImGui_Selectable(ctx, v.id, (val == v.id)) then - engine_lib.setNoteADFactor(v.id); + local is_selected = (val == curval); + if reaper.ImGui_Selectable(ctx, "" .. val, is_selected) then + engine_lib.setSetting(setting, val); end if is_selected then reaper.ImGui_SetItemDefaultFocus(ctx) @@ -733,12 +681,16 @@ end -- Note AD -function AugmentedDiminishedMiniBars() - NoteADSignComboBox(); +function AugmentedDiminishedMiniBars(with_x) + if with_x then + XSeparator() + SL() + end + NoteLenFactorComboBox("Numerator"); SL(); - MiniBarSeparator(); + reaper.ImGui_Text(ctx, "/") SL(); - NoteADFactorComboBox(); + NoteLenFactorComboBox("Denominator"); end function PlayBackMeasureCountComboBox() @@ -760,7 +712,7 @@ function PlayBackMeasureCountComboBox() return ((mnum == -1) and "Mk" or mnum); end - reaper.ImGui_SetNextItemWidth(ctx,45); + reaper.ImGui_SetNextItemWidth(ctx,42); if reaper.ImGui_BeginCombo(ctx, '', label(curm)) then for i=-1,16,1 do local is_selected = (curm == i); @@ -784,18 +736,17 @@ function PlayBackMeasureCountComboBox() TT("Number of measures to rewind, rounded at measure start.\n\n\z 'Mk' stands for Marker mode, the playback will start at the\n\z 'OSS Playback' marker instead. you can set/move/remove it\n\z - it with the button on the right.\z - "); + it with the button on the right."); end function PlaybackButton() reaper.ImGui_PushID(ctx, "playback"); - ButtonGroupImageButton("playback", false, function() - local id = reaper.NamedCommandLookup("_RS0bbcbcb0cb7174a2406403352d006c0573c4c8b4"); - reaper.Main_OnCommand(id, 0); - end, 0, true - ); + if ButtonGroupImageButton("playback", false, { colorset = "Green" } ) then + local id = reaper.NamedCommandLookup("_RS0bbcbcb0cb7174a2406403352d006c0573c4c8b4"); + reaper.Main_OnCommand(id, 0); + end + reaper.ImGui_PopID(ctx); TT("Playback"); end @@ -803,15 +754,90 @@ end function PlaybackSetMarkerButton() reaper.ImGui_PushID(ctx, "playback_marker"); reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_FramePadding(), 8, 4); - ButtonGroupImageButton("marker", false, function() - engine_lib.setPlaybackMarkerAtCurrentPos(); - end, 0, true, false - ); + if ButtonGroupImageButton("marker", false, { colorset = "Green" } ) then + engine_lib.setPlaybackMarkerAtCurrentPos(); + end + reaper.ImGui_PopStyleVar(ctx,1); reaper.ImGui_PopID(ctx); TT("Sets/Moves/Removes the playback marker"); end + +function MagnetMiniBar() + + local label = "##snap" + + local snapElements = { + { setting = "SnapNotes", tt = "Note bounds" , image = "note", width = 7 }, + { setting = "SnapProjectGrid", tt = "Project grid" , image = "pgrid", width = 7 }, + { setting = "SnapItemGrid", tt = "Item grid" , image = "igrid", width = 5 }, + { setting = "SnapItemBounds", tt = "Item bounds" , image = "ibounds", width = 8 } + } + + reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_ItemSpacing(), 2, 4); + reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_ItemInnerSpacing(), 0, 0); + + for k,v in ipairs(snapElements) do + reaper.ImGui_PushID(ctx, "snap_btn_" .. v.setting); + reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_FramePadding(), 8, 4); + local navon = engine_lib.getSetting(v.setting); + if ButtonGroupImageButton("snap_btn_" .. v.image, navon, {colorset="Snap"}) then + engine_lib.setSetting(v.setting, not navon); + end + TT("Navigation snap to " .. v.tt); + reaper.ImGui_PopStyleVar(ctx,1); + reaper.ImGui_PopID(ctx); + if k < #snapElements then + SL() + end + end + + reaper.ImGui_PopStyleVar(ctx, 2); +end + +function EditModeMiniBar() + + local mode = engine_lib.getSetting("EditMode") + local amode = engine_lib.resolveOperationMode().mode + + local modes = { + { name = engine_lib.EditMode.Write, tt = "Forward : Add notes\nBackward : Selective delete (remove notes if pressed)" }, + { name = engine_lib.EditMode.Insert, tt = "Forward : Add notes and shift later ones\nBackward : Delete or shorten notes and shift later ones back"}, + { name = engine_lib.EditMode.Replace, tt = "Forward : Delete (partially or fully) existing notes, and add new ones instead\nBackward : Delete (partially or fully) existing notes" }, + { name = engine_lib.EditMode.Navigate, tt = "Forward : Navigate forward (using snap options)\nBackward : Navigate backward (using snap options)" }, + } + + for k,v in pairs(modes) do + local icon = 'edit_mode_' .. v.name:lower() + local ison = (mode == v.name) + local isactive = (amode == v.name) + + local colorset = "Blue" + + if ison then + if not isactive then + ison = false + end + else + if isactive then + ison = true + colorset = "Blue" + end + end + + if ButtonGroupImageButton(icon, ison, {colorset = colorset}) then + engine_lib.setSetting("EditMode", v.name) + end + TT(v.name .. " Mode\n\n" .. v.tt) + + if k < #modes then + SL() + end + end + +end + function PlaybackWidget() reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_ItemSpacing(), 2, 4); @@ -876,24 +902,45 @@ function SettingSlider(setting, in_label, out_label, tooltip, use_help_interroga end function TargetLine(take) - PlaybackWidget(); - SL(); - if engine_lib.IsSPStepBackModifierKeyPressed() then - if engine_lib.IsSPInsertModifierKeyPressed() then - MiniBarSeparator(0); SL(); - reaper.ImGui_Image(ctx, getImage("indicator_delete"),20,20); SL(); + reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_ItemSpacing(), 2, 4); + reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_ItemInnerSpacing(), 0, 0); + + PlaybackWidget(); SL() + MiniBarSeparator(); SL() + + + reaper.ImGui_PopStyleVar(ctx,2); + + local currentop = engine_lib.resolveOperationMode() + + if currentop.mode == "Insert" then + if currentop.back then + reaper.ImGui_Image(ctx, getImage("indicator_insert_back"),20,20); TT("Insert back (delete and shift)"); SL(); + else + reaper.ImGui_Image(ctx, getImage("indicator_insert_forward"),20,20); ; TT("Insert (add notes and shift)") SL(); + end + elseif currentop.mode == "Replace" then + if currentop.back then + reaper.ImGui_Image(ctx, getImage("indicator_replace_back"),20,20); SL(); TT("Replace back (delete)") SL(); + else + reaper.ImGui_Image(ctx, getImage("indicator_replace_forward"),20,20); SL(); TT("Replace (add notes and remove/patch existing)") SL(); + end + elseif currentop.mode == "Navigate" then + if currentop.back then + reaper.ImGui_Image(ctx, getImage("indicator_navigate_back"),20,20); SL(); TT("Navigate backward") SL(); else - MiniBarSeparator(0); SL(); - reaper.ImGui_Image(ctx, getImage("indicator_back"),20,20); SL(); + reaper.ImGui_Image(ctx, getImage("indicator_navigate_forward"),20,20); SL(); TT("Navigate forward") SL(); end - elseif engine_lib.IsSPInsertModifierKeyPressed() then - MiniBarSeparator(0); SL(); - reaper.ImGui_Image(ctx, getImage("indicator_insert"),20,20); SL(); else - MiniBarSeparator(0); SL(); + if currentop.back then + reaper.ImGui_Image(ctx, getImage("indicator_write_back"),20,20); SL(); TT("Write back (selective delete") SL(); + else + reaper.ImGui_Image(ctx, getImage("indicator_write_forward"),20,20); SL(); TT("Write (add notes)") SL(); + end end + SL(); if not take then @@ -915,11 +962,9 @@ end -- MINIBAR : Settings function SettingsMiniBar() - ButtonGroupImageButton('settings', false, - function() - showsettings = not showsettings; - end, - 0); + if ButtonGroupImageButton('settings', false) then + showsettings = not showsettings; + end end function PlaybackMarkerSettingComboBox() @@ -953,26 +998,62 @@ function PlaybackMarkerSettingComboBox() end -function SPModifierKeyComboBox(setting, info_label) - local combo_items = engine_lib.ModifierKeys; +function AllowedModifierKeyCombinationsForEditMode() + -- All combinations but remove ctrl pedal + local modkey = engine_lib.ModifierKeyLookup[engine_lib.getSetting("StepBackModifierKey")]; + + local filtered = {} + for k, v in ipairs(engine_lib.ModifierKeyCombinations) do + if modkey.vkey ~= v.vkeys[1] and modkey.vkey ~= v.vkeys[2] then + filtered[#filtered+1] = v + end + end + + return filtered +end + +function ClearConflictingModifierKeys() + local sbmk = engine_lib.getSetting("StepBackModifierKey") + local editmodes = { "Navigate", "Replace", "Insert" } + + for k,v in ipairs(editmodes) do + local setting = v.."ModifierKeyCombination" + local modk = engine_lib.getSetting(setting) + local combi = EngineLib.ModifierKeyCombinationLookup[modk]; + + for _, vk in ipairs(combi.vkeys) do + if sbmk == vk then + engine_lib.setSetting(setting, "none") + end + end + end +end + +function StepBackModifierKeyComboBox(callback) + + local setting = "StepBackModifierKey" local modkey = engine_lib.ModifierKeyLookup[engine_lib.getSetting(setting)] or {}; - local label = modkey.name or ""; - local curval = modkey.vkey or 0; + local combo_items = engine_lib.ModifierKeys; + local label = modkey.name; + local curval = modkey.vkey; reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_FramePadding(), 5, 3.5); reaper.ImGui_SetCursorPosY(ctx, reaper.ImGui_GetCursorPosY(ctx)); reaper.ImGui_PushID(ctx, setting); - reaper.ImGui_SetNextItemWidth(ctx, 70); + reaper.ImGui_SetNextItemWidth(ctx, 100); if reaper.ImGui_BeginCombo(ctx, '', label) then for i,v in ipairs(combo_items) do local is_selected = (curval == v.vkey); - if reaper.ImGui_Selectable(ctx, v.name, is_selected) then - engine_lib.setSetting(setting, v.vkey); - end + if is_selected then reaper.ImGui_SetItemDefaultFocus(ctx) end + + if reaper.ImGui_Selectable(ctx, v.name, is_selected) then + engine_lib.setSetting(setting, v.vkey); + ClearConflictingModifierKeys() + end end reaper.ImGui_EndCombo(ctx) end @@ -980,17 +1061,50 @@ function SPModifierKeyComboBox(setting, info_label) reaper.ImGui_PopID(ctx); SL(); - - reaper.ImGui_Text(ctx, info_label); + reaper.ImGui_TextColored(ctx, 0x9090FFFF, "+ sustain pedal") + SL() + reaper.ImGui_Text(ctx, "performs") + SL() + reaper.ImGui_TextColored(ctx, 0xFFA0F0FF, "Back Operation") end -function StepBackSustainPedalModifierKeyComboBox() - SPModifierKeyComboBox("StepBackSustainPedalModifierKey", "+ sustain pedal : performs step back action") -end +function EditModeComboBox(editModeName, callback) + + local combo_items = AllowedModifierKeyCombinationsForEditMode() + local setting = editModeName .. "ModifierKeyCombination" + local current_id = engine_lib.getSetting(setting) + local current_combi = engine_lib.ModifierKeyCombinationLookup[current_id] + + reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_FramePadding(), 5, 3.5); + reaper.ImGui_SetCursorPosY(ctx, reaper.ImGui_GetCursorPosY(ctx)); + reaper.ImGui_PushID(ctx, setting); -function InsertModeSustainPedalModifierKeyComboBox() - SPModifierKeyComboBox("InsertModeSustainPedalModifierKey", ": activates insert mode") + reaper.ImGui_SetNextItemWidth(ctx, 100); + if reaper.ImGui_BeginCombo(ctx, '', current_combi.label) then + for i,v in ipairs(combo_items) do + local is_selected = (current_combi.id == v.id); + + if is_selected then + reaper.ImGui_SetItemDefaultFocus(ctx) + end + + if reaper.ImGui_Selectable(ctx, v.label, is_selected) then + engine_lib.setSetting(setting, v.id); + -- TODO : Reset all collisions + end + end + reaper.ImGui_EndCombo(ctx) + end + reaper.ImGui_PopStyleVar(ctx,1); + reaper.ImGui_PopID(ctx); + + SL() + reaper.ImGui_Text(ctx, "activates") + SL() + reaper.ImGui_TextColored(ctx, 0xFFA0F0FF, ""..editModeName) + SL() + reaper.ImGui_Text(ctx, "edit mode") end @@ -1036,12 +1150,27 @@ function SettingsPanel() reaper.ImGui_EndTabItem(ctx) end - if reaper.ImGui_BeginTabItem(ctx, 'Controls') then ImGui_VerticalSpacer(ctx,5); - StepBackSustainPedalModifierKeyComboBox(); - InsertModeSustainPedalModifierKeyComboBox(); + StepBackModifierKeyComboBox() + EditModeComboBox("Write") + EditModeComboBox("Navigate") + EditModeComboBox("Insert") + EditModeComboBox("Replace") + + curval = engine_lib.getSetting("HideEditModeMiniBar"); + if reaper.ImGui_Checkbox(ctx, "Hide edit mode mini bar", curval) then + engine_lib.setSetting("HideEditModeMiniBar", not curval); + end + SL() + reaper.ImGui_TextColored(ctx, 0xB0B0B0FF, "(?)"); + TT("If you have configured a modifier for all modes,\n\z + and you have set a default mode, you may want to\n\z + get rid of the edit mode mini bar (still, you could\n\z + also want to keep the ability to toggle a mode with a\n\z + mouse click). Up to you!") + curval = engine_lib.getSetting("PedalRepeatEnabled"); if reaper.ImGui_Checkbox(ctx, "Pedal repeat every", curval) then @@ -1055,19 +1184,25 @@ function SettingsPanel() reaper.ImGui_EndTabItem(ctx) end - if reaper.ImGui_BeginTabItem(ctx, 'Step Back') then + if reaper.ImGui_BeginTabItem(ctx, 'Stepping') then ImGui_VerticalSpacer(ctx,5); - curval = engine_lib.getSetting("PreventAddingNotesIfModifierKeyIsPressed"); - if reaper.ImGui_Checkbox(ctx, "Do not add notes if the step back modifier key is pressed", curval) then - engine_lib.setSetting("PreventAddingNotesIfModifierKeyIsPressed", not curval); + curval = engine_lib.getSetting("DoNotRewindOnStepBackIfNothingErased"); + if reaper.ImGui_Checkbox(ctx, "Do not rewind when trying to erase with some pressed keys but nothing was erased", curval) then + engine_lib.setSetting("DoNotRewindOnStepBackIfNothingErased", not curval); end - curval = engine_lib.getSetting("AllowErasingWhenNoteEndDoesNotMatchCursor"); - if reaper.ImGui_Checkbox(ctx, "Erase note ends even if they do not align on cursor", curval) then - engine_lib.setSetting("AllowErasingWhenNoteEndDoesNotMatchCursor", not curval); + curval = engine_lib.getSetting("AllowKeyEventNavigation"); + if reaper.ImGui_Checkbox(ctx, "Allow navigating on key press/release events", curval) then + engine_lib.setSetting("AllowKeyEventNavigation", not curval); end + curval = engine_lib.getSetting("AutoScrollArrangeView"); + if reaper.ImGui_Checkbox(ctx, "Auto-scroll arrange view after editing/navigating", curval) then + engine_lib.setSetting("AutoScrollArrangeView", not curval); + end + + reaper.ImGui_EndTabItem(ctx) end @@ -1096,7 +1231,6 @@ function SettingsPanel() engine_lib.setSetting("KeyPressModeInertiaEnabled", not curval); end - ------------ reaper.ImGui_EndTabItem(ctx) end @@ -1126,6 +1260,28 @@ function SettingsPanel() end end +function NoteLenOptions(grid_mode) + local nlmod = engine_lib.getNoteLenModifier(); + + NoteLenMiniBar(grid_mode); SL() + MiniBarSeparator(); SL() + + if grid_mode then + XSeparator(); SL() + end + + NoteLenModifierMiniBar(grid_mode); + + if nlmod == engine_lib.NoteLenModifier.Tuplet then + SL(); MiniBarSeparator(); SL() + NTupletComboBox() + elseif nlmod == engine_lib.NoteLenModifier.Modified then + SL(); MiniBarSeparator(); SL() + AugmentedDiminishedMiniBars(not grid_mode) + end +end + + function ui_loop() engine_lib.TrackFocus(); @@ -1139,7 +1295,7 @@ function ui_loop() -- Since we use a trick to give back the focus to reaper, we don't want the window to glitch. reaper.ImGui_PushStyleColor(ctx, reaper.ImGui_Col_TitleBgActive(), 0x0A0A0AFF); - local visible, open = reaper.ImGui_Begin(ctx, 'One Small Step v0.9.5', true, flags); + local visible, open = reaper.ImGui_Begin(ctx, 'One Small Step v0.9.6', true, flags); reaper.ImGui_PopStyleColor(ctx,1); if visible then @@ -1158,47 +1314,45 @@ function ui_loop() reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_ItemInnerSpacing(), 0, 0); local nlm = engine_lib.getNoteLenParamSource(); - local nlmod = engine_lib.getNoteLenModifier(); + local amode = engine_lib.getSetting("EditMode") + local emode = engine_lib.resolveOperationMode().mode; - SettingsMiniBar(); - SL(); - MiniBarSeparator(); - SL(); - InputModeMiniBar(); - SL(); - MiniBarSeparator(); - SL(); - ConfSourceMiniBar(); - SL(); - MiniBarSeparator(); + SettingsMiniBar(); SL(); + MiniBarSeparator(); SL(); - if nlm == engine_lib.NoteLenParamSource.OSS then + InputModeMiniBar(); SL(); + MiniBarSeparator(); SL(); + + if not engine_lib.getSetting("HideEditModeMiniBar") then + EditModeMiniBar(); SL(); + MiniBarSeparator(); SL(); + end + + MagnetMiniBar(); SL() + MiniBarSeparator(); SL(); + + ConfSourceMiniBar(); SL(); + MiniBarSeparator(); SL(); + + if nlm == engine_lib.NoteLenParamSource.OSS then + + NoteLenOptions(false) + + elseif nlm == engine_lib.NoteLenParamSource.ProjectGrid then + + ProjectGridLabel(ctx); SL() + XSeparator(); SL(); + NoteLenOptions(true) + + + elseif nlm == engine_lib.NoteLenParamSource.ItemConf then + + ItemGridLabel(ctx,take); SL() + XSeparator(); SL(); + NoteLenOptions(true) - NoteLenMiniBar(); - SL(); - MiniBarSeparator(); - SL(); - NoteLenModifierMiniBar(); - - if nlmod == engine_lib.NoteLenModifier.Tuplet then - SL(); - MiniBarSeparator(); - SL(); - NTupletComboBox(); - elseif nlmod == engine_lib.NoteLenModifier.Modified then - SL(); - MiniBarSeparator(); - SL(); - AugmentedDiminishedMiniBars(); end - elseif nlm == engine_lib.NoteLenParamSource.ProjectGrid then - SL(); - ImGui_ProjectGridLabel(ctx); - elseif nlm == engine_lib.NoteLenParamSource.ItemConf then - SL(); - ImGui_ItemGridLabel(ctx,take); - end reaper.ImGui_PopStyleVar(ctx,3); diff --git a/MIDI Editor/talagan_OneSmallStep/actions/talagan_OneSmallStep Commit.lua b/MIDI Editor/talagan_OneSmallStep/actions/talagan_OneSmallStep Commit.lua deleted file mode 100644 index 4c75e0dcb..000000000 --- a/MIDI Editor/talagan_OneSmallStep/actions/talagan_OneSmallStep Commit.lua +++ /dev/null @@ -1,9 +0,0 @@ --- @noindex --- @author Ben 'Talagan' Babut --- @license MIT --- @description This is part of One Small Step - -package.path = debug.getinfo(1,"S").source:match[[^@?(.*[\/])actions[\/][^\/]-$]] .."?.lua;".. package.path; -local engine_lib = require "classes/engine_lib"; - -engine_lib.reaperActionCommit(); diff --git a/MIDI Editor/talagan_OneSmallStep/actions/talagan_OneSmallStep Commit back.lua b/MIDI Editor/talagan_OneSmallStep/actions/talagan_OneSmallStep Edit Action.lua similarity index 60% rename from MIDI Editor/talagan_OneSmallStep/actions/talagan_OneSmallStep Commit back.lua rename to MIDI Editor/talagan_OneSmallStep/actions/talagan_OneSmallStep Edit Action.lua index 960ebe285..1e84ab572 100644 --- a/MIDI Editor/talagan_OneSmallStep/actions/talagan_OneSmallStep Commit back.lua +++ b/MIDI Editor/talagan_OneSmallStep/actions/talagan_OneSmallStep Edit Action.lua @@ -5,5 +5,10 @@ package.path = debug.getinfo(1,"S").source:match[[^@?(.*[\/])actions[\/][^\/]-$]] .."?.lua;".. package.path; local engine_lib = require "classes/engine_lib"; +local param = select(2, reaper.get_action_context()):match("%- ([^%s]*)%.lua$"); -engine_lib.reaperActionCommitBack(); +if not param or param == "" then + param = "Commit" +end + +engine_lib.reaperAction(param) diff --git a/MIDI Editor/talagan_OneSmallStep/actions/talagan_OneSmallStep Insert Commit back.lua b/MIDI Editor/talagan_OneSmallStep/actions/talagan_OneSmallStep Insert Commit back.lua deleted file mode 100644 index c19a3783b..000000000 --- a/MIDI Editor/talagan_OneSmallStep/actions/talagan_OneSmallStep Insert Commit back.lua +++ /dev/null @@ -1,9 +0,0 @@ --- @noindex --- @author Ben 'Talagan' Babut --- @license MIT --- @description This is part of One Small Step - -package.path = debug.getinfo(1,"S").source:match[[^@?(.*[\/])actions[\/][^\/]-$]] .."?.lua;".. package.path; -local engine_lib = require "classes/engine_lib"; - -engine_lib.reaperActionInsertBack(); diff --git a/MIDI Editor/talagan_OneSmallStep/actions/talagan_OneSmallStep Insert Commit.lua b/MIDI Editor/talagan_OneSmallStep/actions/talagan_OneSmallStep Insert Commit.lua deleted file mode 100644 index fec932021..000000000 --- a/MIDI Editor/talagan_OneSmallStep/actions/talagan_OneSmallStep Insert Commit.lua +++ /dev/null @@ -1,9 +0,0 @@ --- @noindex --- @author Ben 'Talagan' Babut --- @license MIT --- @description This is part of One Small Step - -package.path = debug.getinfo(1,"S").source:match[[^@?(.*[\/])actions[\/][^\/]-$]] .."?.lua;".. package.path; -local engine_lib = require "classes/engine_lib"; - -engine_lib.reaperActionInsert(); diff --git a/MIDI Editor/talagan_OneSmallStep/classes/KeyActivityManager.lua b/MIDI Editor/talagan_OneSmallStep/classes/KeyActivityManager.lua index ac2682d09..89ba698b8 100644 --- a/MIDI Editor/talagan_OneSmallStep/classes/KeyActivityManager.lua +++ b/MIDI Editor/talagan_OneSmallStep/classes/KeyActivityManager.lua @@ -54,6 +54,11 @@ function KeyActivityManager:pullPedalTriggerForTrack(track) return false end +function KeyActivityManager:keyActivityForTrack(track) + local trackid = reaper.GetTrackGUID(track); + return self.activity[trackid]; +end + function KeyActivityManager:forgetPedalTriggerForTrack(track, time, first_hit_multiplier) local trackid = reaper.GetTrackGUID(track); local pedal_activity = self.activity[trackid].pedal; @@ -72,6 +77,17 @@ function KeyActivityManager:forgetPedalTriggerForTrack(track, time, first_hit_mu end end +function KeyActivityManager:lockPedalRepeaterTillNextRelease(track) + local trackid = reaper.GetTrackGUID(track); + local pedal_activity = self.activity[trackid].pedal; + + if not pedal_activity.committed then + return + end + + pedal_activity.last_commit = 1/0 -- inf +end + function KeyActivityManager:updateActivity(track, oss_state) diff --git a/MIDI Editor/talagan_OneSmallStep/classes/engine_lib.lua b/MIDI Editor/talagan_OneSmallStep/classes/engine_lib.lua index a6491bae1..c90c263e0 100644 --- a/MIDI Editor/talagan_OneSmallStep/classes/engine_lib.lua +++ b/MIDI Editor/talagan_OneSmallStep/classes/engine_lib.lua @@ -15,49 +15,69 @@ local KeyReleaseActivityManager = require "KeyReleaseActivityManager"; local KeyPressActivityManager = require "KeyPressActivityManager"; local launchTime = reaper.time_precise(); - +local IsMacos = (reaper.GetOS():find('OSX') ~= nil); ------------- -- Defines +-- Tolerance to detect if events match +local TIME_TOLERANCE = 0.002 +local QN_TOLERANCE = 0.002 +local PPQ_TOLERANCE = 1 + local NoteLenDefs = { - { id = "1", next = "1", prec = "1_2", qn = 4 }, - { id = "1_2", next = "1", prec = "1_4", qn = 2 }, - { id = "1_4", next = "1_2", prec = "1_8", qn = 1 }, - { id = "1_8", next = "1_4", prec = "1_16", qn = 0.5 }, - { id = "1_16", next = "1_8", prec = "1_32", qn = 0.25 }, - { id = "1_32", next = "1_16", prec = "1_64", qn = 0.125 }, - { id = "1_64", next = "1_32", prec = "1_64", qn = 0.0625 } -}; -local AugmentedDiminishedDefs = { - { id = '1/2', mod = 1 / 2.0 }, - { id = '1/3', mod = 1 / 3.0 }, - { id = '2/3', mod = 2 / 3.0 }, - { id = '1/4', mod = 1 / 4.0 }, - { id = '3/4', mod = 3 / 4.0 }, - { id = '1/5', mod = 1 / 5.0 }, - { id = '2/5', mod = 2 / 5.0 }, - { id = '3/5', mod = 3 / 5.0 }, - { id = '4/5', mod = 4 / 5.0 }, - { id = '1/6', mod = 1 / 6.0 }, - { id = '5/6', mod = 5 / 6.0 }, - { id = '1/7', mod = 1 / 7.0 }, - { id = '2/7', mod = 2 / 7.0 }, - { id = '3/7', mod = 3 / 7.0 }, - { id = '4/7', mod = 4 / 7.0 }, - { id = '5/7', mod = 5 / 7.0 }, - { id = '6/7', mod = 6 / 7.0 }, - { id = '1/8', mod = 1 / 8.0 }, - { id = '3/8', mod = 3 / 8.0 }, - { id = '5/8', mod = 5 / 8.0 }, - { id = '7/8', mod = 7 / 8.0 }, - { id = '1/9', mod = 1 / 9.0 }, - { id = '2/9', mod = 2 / 9.0 }, - { id = '4/9', mod = 4 / 9.0 }, - { id = '5/9', mod = 5 / 9.0 }, - { id = '7/9', mod = 7 / 9.0 }, - { id = '8/9', mod = 8 / 9.0 } + { id = "1", next = "1", prec = "1_2", frac = "4" , qn = 4 }, + { id = "1_2", next = "1", prec = "1_4", frac = "2" , qn = 2 }, + { id = "1_4", next = "1_2", prec = "1_8", frac = "1" , qn = 1 }, + { id = "1_8", next = "1_4", prec = "1_16", frac = "1_2" , qn = 0.5 }, + { id = "1_16", next = "1_8", prec = "1_32", frac = "1_4" , qn = 0.25 }, + { id = "1_32", next = "1_16", prec = "1_64", frac = "1_8" , qn = 0.125 }, + { id = "1_64", next = "1_32", prec = "1_64", frac = "1_16", qn = 0.0625 } }; +local NoteLenParamSource = { + OSS = 0, + ProjectGrid = 1, + ItemConf = 2 +} + +local InputMode = { + None = 0, + Punch = 1, + KeyboardRelease = 2, + Action = 3, -- Removed, merged with pedal + KeyboardPress = 4 +} + +local NoteLenModifier = { + Straight = 0, + Dotted = 1, + Triplet = 2, + Tuplet = 3, + Modified = 4 +} + +local EditMode = { + Write = "Write", + Navigate = "Navigate", + Insert = "Insert", + Replace = "Replace" +} + +local ActionTriggers = { + Commit = { action = "Commit", back = false }, + CommitBack = { action = "Commit", back = true }, + + Write = { action = "Write", back = false }, + Navigate = { action = "Navigate", back = false }, + Insert = { action = "Insert", back = false }, + Replace = { action = "Replace", back = false }, + + WriteBack = { action = "Write", back = true }, + NavigateBack = { action = "Navigate", back = true }, + InsertBack = { action = "Insert", back = true }, + ReplaceBack = { action = "Replace", back = true }, +} + local MacOSModifierKeys = { { vkey = 16, name = 'Shift' }, { vkey = 17, name = 'Cmd' }, @@ -71,7 +91,6 @@ local OtherOSModifierKeys = { { vkey = 18, name = 'Alt' } }; -local IsMacos = (reaper.GetOS():find('OSX') ~= nil); local ModifierKeys = IsMacos and MacOSModifierKeys or OtherOSModifierKeys; local NoteLenLookup = {}; @@ -79,59 +98,59 @@ for i,v in ipairs(NoteLenDefs) do NoteLenLookup[v.id] = v; end -local AugmentedDiminishedLookup = {}; -for i,v in ipairs(AugmentedDiminishedDefs) do - AugmentedDiminishedLookup[v.id] = v; -end - local ModifierKeyLookup = {}; for i,v in ipairs(ModifierKeys) do ModifierKeyLookup[v.vkey] = v; end +local ModifierKeyCombinations = {{ label = "None", id = "none", vkeys = {} }} +for i=1, #ModifierKeys do + local m1 = ModifierKeys[i] + ModifierKeyCombinations[#ModifierKeyCombinations+1] = { label = m1.name, id = "" .. m1.vkey, vkeys = { m1.vkey } } +end +for i=1, #ModifierKeys do + local m1 = ModifierKeys[i] + for j=i+1, #ModifierKeys do + m2 = ModifierKeys[j] + ModifierKeyCombinations[#ModifierKeyCombinations+1] = { label = m1.name .. "+" .. m2.name, id = "" .. m1.vkey .. "+" .. m2.vkey, vkeys = { m1.vkey, m2.vkey } } + end +end +local ModifierKeyCombinationLookup = {}; +for i,v in ipairs(ModifierKeyCombinations) do + ModifierKeyCombinationLookup[v.id] = v; +end -local NoteLenParamSource = { - OSS = 0, - ProjectGrid = 1, - ItemConf = 2 -} - -local InputMode = { - None = 0, - Punch = 1, - KeyboardRelease = 2, - Action = 3, -- Removed, merged with pedal - KeyboardPress = 4 -} - -local NoteLenModifier = { - Straight = 0, - Dotted = 1, - Triplet = 2, - Tuplet = 3, - Modified = 4 -} ------------- -- Settings local SettingDefs = { - PlaybackMeasureCount = { type = "int", default = -1 }, -- -1 is marker mode + StepBackModifierKey = { type = "int", default = IsMacOs and 16 or 16 }, + + WriteModifierKeyCombination = { type = "string", default = "none" }, + InsertModifierKeyCombination = { type = "string", default = IsMacos and "17" or "17" }, + NavigateModifierKeyCombination = { type = "string", default = IsMacos and "18" or "18" }, + ReplaceModifierKeyCombination = { type = "string", default = IsMacos and "17+18" or "17+18" }, + + HideEditModeMiniBar = { type = "bool", default = false }, + Mode = { type = "int", default = InputMode.KeyboardRelease }, + EditMode = { type = "string", default = EditMode.Write }, + + PlaybackMeasureCount = { type = "int", default = -1 }, -- -1 is marker mode NoteLenParamSource = { type = "int", default = NoteLenParamSource.OSS }, - NoteLenADSign = { type = "string", default = "+" }, - NoteADFactor = { type = "string", default = "1/2" }, + NoteLenFactorDenominator = { type = "int", default = 1 }, + NoteLenFactorNumerator = { type = "int", default = 1 }, TupletDivision = { type = "int", default = 4 }, NoteLen = { type = "string", default = "1_4"}, NoteLenModifier = { type = "int", default = NoteLenModifier.Straight }, ------ + PlaybackMarkerPolicyWhenClosed = { type = "string", default = "Keep visible" }, + AllowTargetingFocusedMidiEditors = { type = "bool", default = true }, AllowTargetingNonSelectedItemsUnderCursor = { type = "bool", default = false }, AllowCreateItem = { type = "bool", default = false }, - AllowErasingWhenNoteEndDoesNotMatchCursor = { type = "bool", default = true }, - PlaybackMarkerPolicyWhenClosed = { type = "string", default = "Keep visible" }, - StepBackSustainPedalModifierKey = { type = "int", default = 16 }, - InsertModeSustainPedalModifierKey = { type = "int", default = 17 }, - PreventAddingNotesIfModifierKeyIsPressed = { type = "bool", default = true}, + + DoNotRewindOnStepBackIfNothingErased = { type = "bool", default = true}, CleanupJsfxAtClosing = { type = "bool", default = true}, SelectInputNotes = { type = "bool", default = true}, ------ @@ -143,7 +162,17 @@ local SettingDefs = { PedalRepeatEnabled = { type = "bool" , default = true }, PedalRepeatTime = { type = "double", default = 0.200, min = 0.05, max = 0.5 }, - PedalRepeatFirstHitMultiplier = { type = "int", default = 4, min = 1, max = 10 } + PedalRepeatFirstHitMultiplier = { type = "int", default = 4, min = 1, max = 10 }, + + Snap = { type = "bool", default = false }, + SnapNotes = { type = "bool", default = true }, + SnapProjectGrid = { type = "bool", default = true }, + SnapItemGrid = { type = "bool", default = true }, + SnapItemBounds = { type = "bool", default = true }, + + AutoScrollArrangeView = { type = "bool", default = true }, + + AllowKeyEventNavigation = { type = "bool", default = false } }; local function unsafestr(str) @@ -215,12 +244,6 @@ local function getInputMode() return getSetting("Mode") local function setNoteLenParamSource(m) return setSetting("NoteLenParamSource", m) end local function getNoteLenParamSource() return getSetting("NoteLenParamSource") end -local function setNoteADSign(plus_or_minus) return setSetting("NoteLenADSign", plus_or_minus) end -local function getNoteADSign() return getSetting("NoteLenADSign") end - -local function setNoteADFactor(fraction_string) return setSetting("NoteADFactor", fraction_string) end -local function getNoteADFactor() return getSetting("NoteADFactor") end - local function setTupletDivision(m) return setSetting("TupletDivision", m) end local function getTupletDivision() return getSetting("TupletDivision") end @@ -230,6 +253,8 @@ local function getNoteLen() return getSetting("NoteLen") local function setNoteLenModifier(nl) return setSetting("NoteLenModifier", nl) end local function getNoteLenModifier() return getSetting("NoteLenModifier") end +local function getNoteLenFactorNumerator() return getSetting("NoteLenFactorNumerator") end +local function getNoteLenFactorDenominator() return getSetting("NoteLenFactorDenominator") end --------------- -- FOCUS TOOLS @@ -278,44 +303,61 @@ end ----------------------------------- -- Triggers for external actions --- The three functions are used to communicate between the independent actions and OSS +-- These functions are used to communicate between the independent actions and OSS + +local function validateActionTrigger(action_name) + if ActionTriggers[action_name] == nil then + error("Trying to use unknown action trigger :" .. action_name) + end +end + local function setActionTrigger(action_name) - reaper.SetExtState("OneSmallStep", action_name, tostring(reaper.time_precise()), false); + validateActionTrigger(action_name) + reaper.SetExtState("OneSmallStep", action_name .. "ActionTrigger", tostring(reaper.time_precise()), false); end local function getActionTrigger(action_name) - return tonumber(reaper.GetExtState("OneSmallStep", action_name)); + validateActionTrigger(action_name) + return tonumber(reaper.GetExtState("OneSmallStep", action_name .. "ActionTrigger")); end local function clearActionTrigger(action_name) - reaper.DeleteExtState("OneSmallStep", action_name, true); + validateActionTrigger(action_name) + reaper.DeleteExtState("OneSmallStep", action_name .. "ActionTrigger", true); end -local function setCommitActionTrigger() return setActionTrigger( "CommitActionTrigger") end -local function getCommitActionTrigger() return getActionTrigger( "CommitActionTrigger") end -local function clearCommitActionTrigger() return clearActionTrigger( "CommitActionTrigger") end - -local function setCommitBackActionTrigger() return setActionTrigger( "CommitBackActionTrigger") end -local function getCommitBackActionTrigger() return getActionTrigger( "CommitBackActionTrigger") end -local function clearCommitBackActionTrigger() return clearActionTrigger( "CommitBackActionTrigger") end - -local function setInsertActionTrigger() return setActionTrigger( "InsertActionTrigger") end -local function getInsertActionTrigger() return getActionTrigger( "InsertActionTrigger") end -local function clearInsertActionTrigger() return clearActionTrigger( "InsertActionTrigger") end +function clearAllActionTriggers() + for k,v in pairs(ActionTriggers) do + clearActionTrigger(k) + end +end -local function setInsertBackActionTrigger() return setActionTrigger( "InsertBackActionTrigger") end -local function getInsertBackActionTrigger() return getActionTrigger( "InsertBackActionTrigger") end -local function clearInsertBackActionTrigger() return clearActionTrigger( "InsertBackActionTrigger") end ------------ -- Our manager for the Action/Pedal mode (use generic one) local APActivityManager = KeyActivityManager:new(); - -- Our manager for the Key Release input mode local KRActivityManager = KeyReleaseActivityManager:new(); - -- Our manager for the Key Press input mode local KPActivityManager = KeyPressActivityManager:new(); + +local function currentKeyEventManager() + local manager = nil + local mode = getInputMode(); + + -- We have different managers for all modes + -- But their architecture is identical and compliant + if mode == InputMode.KeyboardPress then + manager = KPActivityManager; + elseif mode == InputMode.KeyboardRelease then + manager = KRActivityManager; + else + manager = APActivityManager; + end + + return manager +end + ------------- -- Playback @@ -338,7 +380,7 @@ function setPlaybackMarkerAtPos(pos) reaper.DeleteProjectMarkerByIndex(0, id); end - if (mpos == nil) or math.abs(pos - mpos) > 0.001 then + if (mpos == nil) or math.abs(pos - mpos) > TIME_TOLERANCE then reaper.AddProjectMarker2(0, false, pos, 0, "OSS Playback", -1, reaper.ColorToNative(0,200,255)|0x1000000); end reaper.Undo_EndBlock("One Small Step - Set playback marker", -1); @@ -359,33 +401,60 @@ end ------------------ -local function IsSPStepBackModifierKeyPressed() - -- Avoid inconsistencies and only follow events during the lifetime of the plugin, so use launchTime - -- This will prevent bugs from a session to another (when for example the plugin crashes) - local keys = reaper.JS_VKeys_GetState(launchTime); - local c1 = keys:byte(getSetting("StepBackSustainPedalModifierKey")); - return (c1 == 1); -end -local function getSPStepBackModifierKey() - return ModifierKeyLookup[getSetting("StepBackSustainPedalModifierKey")]; +local function validateModifierKeyCombination(id) + if ModifierKeyCombinationLookup[id] == nil then + error("Trying to use unknown modifier key combination with id " .. id) + end end -local function IsSPInsertModifierKeyPressed() +-- Returns the state of the modifier key linked to the function "function_name" +local function IsModifierKeyCombinationPressed(id) + validateModifierKeyCombination(id) + + if id == "none" then + return false + end + -- Avoid inconsistencies and only follow events during the lifetime of the plugin, so use launchTime -- This will prevent bugs from a session to another (when for example the plugin crashes) - local keys = reaper.JS_VKeys_GetState(launchTime); - local c1 = keys:byte(getSetting("InsertModeSustainPedalModifierKey")); - return (c1 == 1); + local keys = reaper.JS_VKeys_GetState(launchTime); + local combi = ModifierKeyCombinationLookup[id] + + for k, v in ipairs(combi.vkeys) do + local c1 = keys:byte(v); + if not (c1 ==1) then + return false + end + end + + return true end -local function getSPInsertModifierKey() - return ModifierKeyLookup[getSetting("InsertModeSustainPedalModifierKey")]; + +local function IsStepBackModifierKeyPressed() + local keys = reaper.JS_VKeys_GetState(launchTime); + return (keys:byte(getSetting("StepBackModifierKey")) == 1) end ----------------- +local function precpow2(n) + local b = 0 + local a = (n >> b) + while a > 0 do + b = b + 1 + a = (n >> b) + end + return (1 << (b-1)) +end + +local function tupletFactor(div) + return precpow2(div)/div +end + local function getNoteLenModifierFactor() - local m = getNoteLenModifier(); + local m = getNoteLenModifier() + local nls = getNoteLenParamSource() if m == NoteLenModifier.Straight then return 1.0; @@ -394,13 +463,16 @@ local function getNoteLenModifierFactor() elseif m == NoteLenModifier.Triplet then return 2/3.0; elseif m == NoteLenModifier.Modified then - local sign = getNoteADSign(); - local factor = AugmentedDiminishedLookup[getNoteADFactor()].mod; - - return 1 + (sign == '+' and 1 or -1) * factor; + return getSetting("NoteLenFactorNumerator") / getSetting("NoteLenFactorDenominator"); elseif m == NoteLenModifier.Tuplet then local div = getTupletDivision(); - return 2.0/div; + + if nls == NoteLenParamSource.OSS then + return tupletFactor(div) + else + -- In grid mode, we just return 1/n + return 1/div + end end return 1.0; @@ -422,18 +494,184 @@ local function getNoteLenQN() return NoteLenLookup[nl].qn; end + +-------------------- + +local function swingNoteLenQN(measureStartQN, posQN, noteLenQN, swing) + local elapsedDoubleBeats = (posQN - measureStartQN)/(2*noteLenQN) + -- Hack, it may happen that the cursor is just before the measure start + if elapsedDoubleBeats < 0 then + elapsedDoubleBeats = 0 + end + + local eaten = elapsedDoubleBeats - math.floor(elapsedDoubleBeats) + if eaten > 1 - QN_TOLERANCE/noteLenQN then + -- Hack : cursor may be very close to next double beat. + eaten = 0 + end + + local onbeat = (1 + swing * 0.5) + local offbeat = (1 - swing * 0.5) + + if (2 * eaten) < onbeat - (QN_TOLERANCE / noteLenQN) then + return (noteLenQN * onbeat) + else + return (noteLenQN * offbeat) + end +end + +local function resolveNoteLenQN(take) + + local nlm = getNoteLenParamSource() + + local cursorTime = reaper.GetCursorPosition() + local cursorQN = reaper.TimeMap2_timeToQN(0, cursorTime) + local cursorMes = reaper.TimeMap_QNToMeasures(0, cursorQN) + local _, measureStartQN, measureEndQN = reaper.TimeMap_GetMeasureInfo(0, cursorMes - 1) + + if math.abs(cursorQN - measureEndQN) < QN_TOLERANCE then + -- We're on the measure end, advance 1 measure + cursorMes = cursorMes + 1 + _, measureStartQN, measureEndQN = reaper.TimeMap_GetMeasureInfo(0, cursorMes - 1) + end + + if nlm == NoteLenParamSource.OSS then + return getNoteLenQN() * getNoteLenModifierFactor() + elseif nlm == NoteLenParamSource.ProjectGrid then + + local _, division, swingmode, swing = reaper.GetSetProjectGrid(0, false) + local noteLenQN = division * 4 + local multFactor = getNoteLenQN() + + local baselen = 1 + if swingmode == 0 then + -- No swing + baselen = noteLenQN + elseif swingmode == 3 then + -- Project Grid is set to "measure" + baselen = (measureEndQN - measureStartQN) + else + -- Swing + if multFactor > 1 then + baselen = noteLenQN + else + baselen = swingNoteLenQN(measureStartQN, cursorQN, noteLenQN, swing) + end + end + + return baselen * getNoteLenQN() * getNoteLenModifierFactor() + + else + local gridLenQN, swing, noteLenQN = reaper.MIDI_GetGrid(take); + local multFactor = getNoteLenQN() + + if noteLenQN == 0 then + noteLenQN = gridLenQN + end + + local baselen = 1 + if swing == 0 then + baselen = noteLenQN + else + -- Swing + if multFactor > 1 then + baselen = noteLenQN + else + baselen = swingNoteLenQN(measureStartQN, cursorQN, noteLenQN, swing) + end + end + + return baselen * getNoteLenQN() * getNoteLenModifierFactor() + end +end + +local function resolveOperationMode(look_for_action_triggers) + local bk = IsStepBackModifierKeyPressed() + local mode = getSetting("EditMode") + local triggered_by_action = false + + local editModes = { + { name = "Write", prio = 4 }, + { name = "Navigate", prio = 3 }, + { name = "Insert", prio = 2 }, + { name = "Replace", prio = 1 }, + } + + local activemodes = {} + for k, editmode in ipairs(editModes) do + local setting = getSetting(editmode.name .. "ModifierKeyCombination") + local combi = ModifierKeyCombinationLookup[setting] + local pressed = IsModifierKeyCombinationPressed(combi.id) + if pressed then + activemodes[#activemodes + 1] = { mode = editmode.name, combi = combi, prio = editmode.prio } + end + end + + table.sort(activemodes, function(e1,e2) + -- Priorize items that have their track selected + local l1 = #e1.combi.vkeys + local l2 = #e2.combi.vkeys + + if l1 == l2 then + return e1.prio < e2.prio + end + + return l1 > l2; + end) + + if #activemodes > 0 then + mode = activemodes[1].mode + end + + if look_for_action_triggers then + for k, v in pairs(ActionTriggers) do + local has_triggered = getActionTrigger(k) + if has_triggered then + if v.action ~= "Commit" then + -- If it's a commit, use current mode, else use the mode linked to the trigger + mode = v.action + end + triggered_by_action = true + break + end + end + end + + return { + mode = mode, + back = bk + } +end + ------------------- -local function MediaItemContainsCursor(mediaItem, cusorPos) + +local function KeepEditCursorOnScreen() + local start_time, end_time = reaper.GetSet_ArrangeView2(0, false, 0, 0, 0, 0) + local cursor_time = reaper.GetCursorPosition() + local diff_time = end_time - start_time + local bound = 0.05 + local alpha = 0.25 + + if cursor_time < start_time + bound * diff_time then + reaper.GetSet_ArrangeView2(0, true, 0, 0, cursor_time - diff_time * alpha, cursor_time + diff_time * (1 - alpha)) + end + + if cursor_time > end_time - bound * diff_time then + reaper.GetSet_ArrangeView2(0, true, 0, 0, cursor_time - diff_time * (1-alpha), cursor_time + diff_time * alpha) + end +end + + +local function MediaItemContainsCursor(mediaItem, CursorPos) local pos = reaper.GetMediaItemInfo_Value(mediaItem, "D_POSITION") local len = reaper.GetMediaItemInfo_Value(mediaItem, "D_LENGTH") - local fudge = 0.002; - local left = pos - fudge; - local right = pos + len + fudge; + local left = pos - TIME_TOLERANCE; + local right = pos + len + TIME_TOLERANCE; -- Only keep items that contain the cursor pos - return (cusorPos >= left) and (cusorPos <= right); + return (CursorPos >= left) and (CursorPos <= right); end @@ -576,55 +814,9 @@ end --------------------------- -local function resolveNoteLenQN(take) - - local nlm = getNoteLenParamSource(); - - if nlm == NoteLenParamSource.OSS then - return getNoteLenQN() * getNoteLenModifierFactor(); - elseif nlm == NoteLenParamSource.ProjectGrid then - - local _, qn, swing, _ = reaper.GetSetProjectGrid(0, false); - - if swing == 3 then - -- Project Grid is set to "measure" - local pos = reaper.GetCursorPosition(); - local posqn = reaper.TimeMap2_timeToQN(0, pos); - local posm = reaper.TimeMap_QNToMeasures(0, posqn); - - local _, measureStart, measureEnd = reaper.TimeMap_GetMeasureInfo(0, posm - 1); - return measureEnd - measureStart; - else - return qn * 4; - end - - else - local grid_len, swing, note_len = reaper.MIDI_GetGrid(take); - - if note_len == 0 then - note_len = grid_len; - end - - return note_len; - end -end - --- Commits the currently held notes into the take -local function justStepBack() - - local note_len = resolveNoteLenQN(nil); - local cursorTime = reaper.GetCursorPosition() - local cursorQN = reaper.TimeMap2_timeToQN(0, cursorTime) - local rewindTime = reaper.TimeMap2_QNToTime(0, cursorQN - note_len) - - reaper.Undo_BeginBlock(); - reaper.SetEditCurPos(rewindTime, false, false); - reaper.Undo_EndBlock("One Small Step: Stepping back",-1); -end - local function CreateItemIfMissing(track) - local newitem = reaper.CreateNewMIDIItemInProj(track, reaper.GetCursorPosition(), reaper.GetCursorPosition() + 0.001, false); + local newitem = reaper.CreateNewMIDIItemInProj(track, reaper.GetCursorPosition(), reaper.GetCursorPosition() + TIME_TOLERANCE, false); take = reaper.GetMediaItemTake(newitem, 0); local _, tname = reaper.GetTrackName(track); reaper.GetSetMediaItemTakeInfo_String(take, "P_NAME", tname ..os.date(' - %Y%m%d%H%M%S'), true); @@ -635,15 +827,16 @@ end local function GetNote(take, ni) local _, selected, muted, startPPQ, endPPQ, chan, pitch, vel = reaper.MIDI_GetNote(take, ni); return { - selected = selected, - muted = muted, - pitch = pitch, - startPPQ = startPPQ, - endPPQ = endPPQ, - chan = chan, - pitch = pitch, - vel = vel, - index = ni + index = ni, + selected = selected, + muted = muted, + pitch = pitch, + chan = chan, + vel = vel, + startPPQ = startPPQ, + startQN = reaper.MIDI_GetProjQNFromPPQPos(take, startPPQ), + endPPQ = endPPQ, + endQN = reaper.MIDI_GetProjQNFromPPQPos(take, endPPQ) }; end @@ -651,354 +844,875 @@ local function SetNote(take, n, nosort) reaper.MIDI_SetNote(take, n.index, n.selected, n.muted, n.startPPQ, n.endPPQ, n.chan, n.pitch, n.vel, nosort) end --- Commits the currently held notes into the take -local function commit(take, notes_to_add, notes_to_extend) - - local insertModeOn = IsSPInsertModifierKeyPressed() or getInsertActionTrigger(); +local function bool2sign(b) + return ((b == true) and (1) or (-1)) +end - local note_len = resolveNoteLenQN(take); - local mediaItem = reaper.GetMediaItemTake_Item(take) - local track = reaper.GetMediaItemTake_Track(take) +local function noteStartsAfterPPQ(note, limit, strict) + return note.startPPQ > limit + bool2sign(strict) * PPQ_TOLERANCE +end +local function noteStartsBeforePPQ(note, limit, strict) + return note.startPPQ < limit - bool2sign(strict) * PPQ_TOLERANCE +end +local function noteEndsAfterPPQ(note, limit, strict) + return note.endPPQ > limit + bool2sign(strict) * PPQ_TOLERANCE +end +local function noteEndsBeforePPQ(note, limit, strict) + return note.endPPQ < limit - bool2sign(strict) * PPQ_TOLERANCE +end - local cursorTime = reaper.GetCursorPosition() - local cursorQN = reaper.TimeMap2_timeToQN(0, cursorTime) - local advanceQN = cursorQN + note_len; - local advanceTime = reaper.TimeMap2_QNToTime(0, advanceQN) +local function noteEndsOnPPQ(note, limit) + return math.abs(note.endPPQ - limit) < PPQ_TOLERANCE +end - local cursorPPQ = reaper.MIDI_GetPPQPosFromProjTime(take, cursorTime) - local advancePPQ = reaper.MIDI_GetPPQPosFromProjTime(take, advanceTime) +local function noteStartsOnPPQ(note, limit) + return math.abs(note.startPPQ - limit) < PPQ_TOLERANCE +end - local newMaxQN = advanceQN +local function setNewNoteBounds(note, take, startPPQ, endPPQ, startOffsetQN, endOffsetQN) + note.startQN = reaper.MIDI_GetProjQNFromPPQPos(take, startPPQ) + startOffsetQN + note.endQN = reaper.MIDI_GetProjQNFromPPQPos(take, endPPQ) + endOffsetQN + note.startPPQ = reaper.MIDI_GetPPQPosFromProjQN(take, note.startQN ) + note.endPPQ = reaper.MIDI_GetPPQPosFromProjQN(take, note.endQN ) +end - local extcount = 0; - local addcount = 0; +local function moveComparatorHelper(v, cursor, best, direction, mode) - reaper.Undo_BeginBlock(); + local tolerance = TIME_TOLERANCE + if mode == "PPQ" then + tolerance = PPQ_TOLERANCE + end - -- First, move some notes if insert mode is on - if insertModeOn then - local _, notecnt, _, _ = reaper.MIDI_CountEvts(take) - local ni = 0 + if direction > 0 then + if (v > cursor + tolerance) and ((best == nil) or (v < best)) then + best = v + end + else + if (v < cursor - tolerance) and ((best == nil) or (v > best)) then + best = v + end + end - while (ni < notecnt) do - local n = GetNote(take, ni); - local startsAfterCursor = (cursorPPQ - 1 < n.startPPQ) + return best +end - if startsAfterCursor then - local startQN = reaper.MIDI_GetProjQNFromPPQPos(take, n.startPPQ) + note_len - local endQN = reaper.MIDI_GetProjQNFromPPQPos(take, n.endPPQ) + note_len - reaper.MIDI_SetNote(take, ni, nil, nil, - reaper.MIDI_GetPPQPosFromProjQN(take, startQN), - reaper.MIDI_GetPPQPosFromProjQN(take, endQN), - nil, nil, nil, true) +local function gridSnapHelper(type, direction, cursorTime, cursorQN, bestJumpTime, take, itemStartTime, itemEndTime) - -- For updating item extents - if endQN > newMaxQN then - newMaxQN = endQN - end - end + local grid_len, swing = nil , nil - ni = ni + 1 + if type == "ITEM" then + grid_len, swing, _ = reaper.MIDI_GetGrid(take) + else + _, grid_len, swingmode, swing = reaper.GetSetProjectGrid(0, false) + grid_len = grid_len * 4 -- put back in QN + if swingmode ~= 1 then + swing = 0 end end - -- Try to extend existing notes - if #notes_to_extend > 0 then - local _, notecnt, _, _ = reaper.MIDI_CountEvts(take); + local cursorBars = reaper.TimeMap_QNToMeasures(0, cursorQN) - 1 + local _, measureStartQN, measureEndQN = reaper.TimeMap_GetMeasureInfo(0, cursorBars) - for _, exnote in pairs(notes_to_extend) do + if cursorBars > 0 and direction < 0 and math.abs(cursorQN - measureStartQN) < QN_TOLERANCE then + -- Cursor is aligned on the beginning of a measure but we're going back. + -- Work with the precedent measure. + cursorBars = cursorBars - 1 + _, measureStartQN, measureEndQN = reaper.TimeMap_GetMeasureInfo(0, cursorBars) + end - -- Search for a note that could be extended (matches all conditions) - local ni = 0; - local found = false; + -- Start with window, and slide - while (ni < notecnt) do + local parity = 1 - local _, _, _, _, endPPQ, chan, pitch, _ = reaper.MIDI_GetNote(take, ni); + local oddOffset = grid_len * (1 + swing * 0.5) + local evenOffset = grid_len * (1 - swing * 0.5) - local endsMatchesCursor = (math.abs(endPPQ - cursorPPQ) < 1.0) + local prec = measureStartQN + local next = prec + ((parity == 1) and (oddOffset) or (evenOffset)) - -- Extend the note if found - if endsMatchesCursor and chan == exnote.chan and pitch == exnote.note then - reaper.MIDI_SetNote(take, ni, nil, nil, nil, advancePPQ, nil, nil, nil, true); - extcount = extcount + 1; - found = true - end + while next < (cursorQN - QN_TOLERANCE) do + parity = parity ~ 1 + prec = next + next = prec + ((parity == 1) and (oddOffset) or (evenOffset)) + end - ni = ni + 1; + if math.abs(cursorQN - next) < QN_TOLERANCE then + parity = parity ~ 1 + next = next + ((parity == 1) and (oddOffset) or (evenOffset)) + end + + local precTime = reaper.TimeMap2_QNToTime(0, prec) + local nextTime = reaper.TimeMap2_QNToTime(0, next) + local msTime = reaper.TimeMap2_QNToTime(0, measureStartQN) + local meTime = reaper.TimeMap2_QNToTime(0, measureEndQN) + + -- Only add these times if they belong to the item (outside, consider there's no grid) + if type == "PROJECT" or (precTime >= itemStartTime and precTime <= itemEndTime) then + bestJumpTime = moveComparatorHelper(precTime, cursorTime, bestJumpTime, direction, "TIME") + end + if type == "PROJECT" or (nextTime >= itemStartTime and nextTime <= itemEndTime) then + bestJumpTime = moveComparatorHelper(nextTime, cursorTime, bestJumpTime, direction, "TIME") + end + if type == "PROJECT" or (msTime >= itemStartTime and msTime <= itemEndTime) then + bestJumpTime = moveComparatorHelper(msTime, cursorTime, bestJumpTime, direction, "TIME") + end + if type == "PROJECT" or (meTime >= itemStartTime and meTime <= itemEndTime) then + bestJumpTime = moveComparatorHelper(meTime, cursorTime, bestJumpTime, direction, "TIME") + end + + return bestJumpTime +end + + +-- Resolves the next snap point. +-- Track can be nil (won't happen) +local function nextSnap(track, direction, reftime, options) + + local cursorTime = reftime -- I don't want to rename everything ... + local cursorQN = reaper.TimeMap2_timeToQN(0, cursorTime) + local bestJumpTime = nil + local maxTime = 0 + + if options.enabled and track then + + local itemCount = reaper.CountTrackMediaItems(track) + local ii = 0 + + -- For optimization, we should randomize the order of iteration over the items + while ii < itemCount do + local mediaItem = reaper.GetTrackMediaItem(track, ii) + + local itemStartTime = reaper.GetMediaItemInfo_Value(mediaItem, "D_POSITION") + local itemEndTime = itemStartTime + reaper.GetMediaItemInfo_Value(mediaItem, "D_LENGTH") + + if (maxTime ~= nil) or (itemEndTime > maxTime) then + maxTime = itemEndTime end - if not found then - -- Could not find a note to extend... create one ! - notes_to_add[#notes_to_add+1] = exnote; + -- A few conditions to avoid exploring the item if not needed + if (direction > 0) then + if (itemEndTime < cursorTime) or ((bestJumpTime ~= nil) and (bestJumpTime < itemStartTime)) then + goto nextitem + end + else + if (itemStartTime > cursorTime) or ((bestJumpTime ~= nil) and (bestJumpTime > itemEndTime)) then + goto nextitem + end end - end + if options.itemBounds then + bestJumpTime = moveComparatorHelper(itemStartTime, cursorTime, bestJumpTime, direction, "TIME") + bestJumpTime = moveComparatorHelper(itemEndTime, cursorTime, bestJumpTime, direction, "TIME") + end + + if options.notes or options.itemGrid then + local takeCount = reaper.GetMediaItemNumTakes(mediaItem) + local ti = 0 + + while ti < takeCount do + + local take = reaper.GetMediaItemTake(mediaItem, ti) + + local itemStartPPQ = reaper.MIDI_GetPPQPosFromProjTime(take, itemStartTime) + local itemEndPPQ = reaper.MIDI_GetPPQPosFromProjTime(take, itemEndTime) + local cursorPPQ = reaper.MIDI_GetPPQPosFromProjTime(take, cursorTime) + local bestJumpPPQ = nil + + if options.notes then + local _, notecnt, _, _ = reaper.MIDI_CountEvts(take) + local ni = 0 + + while (ni < notecnt) do + local n = GetNote(take, ni) + + bestJumpPPQ = moveComparatorHelper(n.startPPQ, cursorPPQ, bestJumpPPQ, direction, "PPQ") + bestJumpPPQ = moveComparatorHelper(n.endPPQ, cursorPPQ, bestJumpPPQ, direction, "PPQ") + + ni = ni+1 + end -- end note iteration + + if bestJumpPPQ then + -- Found a snap note inside item, convert back to time and compare to already found bestJumpTime + local bjt = reaper.TimeMap2_QNToTime(0, reaper.MIDI_GetProjQNFromPPQPos(take, bestJumpPPQ)) + bestJumpTime = moveComparatorHelper(bjt, cursorTime, bestJumpTime, direction, "TIME") + end + end + + if options.itemGrid then + bestJumpTime = gridSnapHelper("ITEM", direction, cursorTime, cursorQN, bestJumpTime, take, itemStartTime, itemEndTime) + end + + ti = ti + 1 + end -- end take iteration + + end + + ::nextitem:: + ii = ii+1 + end -- end item iteration + end -- end options.enabled + + if options.projectGrid then + -- SWS version of BR_GetNextGrid has a bug, use my own implementation + bestJumpTime = gridSnapHelper("PROJECT", direction, cursorTime, cursorQN, bestJumpTime) end - -- Add new notes - for k,v in pairs(notes_to_add) do - reaper.MIDI_InsertNote(take, getSetting("SelectInputNotes"), false, cursorPPQ, advancePPQ, v.chan, v.note, v.velocity) - addcount = addcount + 1; + -- Add track boundaries + bestJumpTime = moveComparatorHelper(0, cursorTime, bestJumpTime, direction, "TIME") + bestJumpTime = moveComparatorHelper(maxTime, cursorTime, bestJumpTime, direction, "TIME") + + -- Safety + if bestJumpTime == nil then + if maxTime == nil then + maxTime = cursorTime + end + bestJumpTime = (direction > 0) and (cursorTime) or 0 end - -- Advance and mark dirty - reaper.MIDI_Sort(take) - reaper.UpdateItemInProject(mediaItem) - reaper.SetEditCurPos(advanceTime, false, false); + return { + time = bestJumpTime, + qn = reaper.TimeMap2_timeToQN(0, bestJumpTime) + } +end - -- Grow the midi item if needed - local itemStartTime = reaper.GetMediaItemInfo_Value(mediaItem, "D_POSITION") - local itemLength = reaper.GetMediaItemInfo_Value(mediaItem, "D_LENGTH") - local itemEndTime = itemStartTime + itemLength; - local newMaxTime = reaper.TimeMap2_QNToTime(0, newMaxQN) +local function snapOptions() + return { + enabled = getSetting("Snap"), + itemBounds = getSetting("SnapItemBounds"), + notes = getSetting("SnapNotes"), + itemGrid = getSetting("SnapItemGrid"), + projectGrid = getSetting("SnapProjectGrid") + } +end - if(itemEndTime >= newMaxTime) then - -- Cool, the item is big enough - else - local itemStartQN = reaper.TimeMap2_timeToQN(0, itemStartTime) - local itemEndQN = reaper.TimeMap2_timeToQN(0, newMaxTime) +local function nextSnapFromCursor(track, direction) + return nextSnap(track, direction, reaper.GetCursorPosition(), snapOptions()) +end - reaper.MIDI_SetItemExtents(mediaItem, itemStartQN, itemEndQN) - reaper.UpdateItemInProject(mediaItem); +local function navigate(track, direction) + local ns = nextSnapFromCursor(track, direction) + + reaper.Undo_BeginBlock(); + reaper.SetEditCurPos(ns.time, false, false); + if getSetting("AutoScrollArrangeView") then + KeepEditCursorOnScreen() end + reaper.Undo_EndBlock("One Small Step: " .. ((direction > 0) and ("advanced") or ("stepped back")),-1); +end - -- Mark item as dirty - reaper.MarkTrackItemsDirty(track, mediaItem) - local description = ""; +local function navigateForward(track) + navigate(track, 1) +end - if extcount == 0 then - if addcount == 0 then - description = "Advance/Insert rest" - else - description = "Add " .. addcount .. " note(s)" - end - else - if addcount == 0 then - description = "Extend " .. extcount .. " note(s)" +-- Commits the currently held notes into the take +local function navigateBack(track) + navigate(track, -1) +end + + +local function commitDescription(direction, addcount, remcount, shcount, extcount, mvcount) + local description = {} + + if shcount+addcount+remcount+shcount+extcount == 0 then + if direction > 0 then + description[#description+1] = "advanced" else - description = "Add " .. addcount .. " note(s) and extend " .. extcount .. " note(s)" + description[#description+1] = "stepped back" end end + if addcount > 0 then + description[#description+1] = "added " .. addcount .. " notes" + end + if remcount > 0 then + description[#description+1] = "removed " .. remcount .. " notes" + end + if mvcount > 0 then + description[#description+1] = "moved " .. mvcount .. " notes" + end + if shcount > 0 then + description[#description+1] = "shortened " .. shcount .. " notes" + end + if extcount > 0 then + description[#description+1] = "extended " .. extcount .. " notes" + end - reaper.Undo_EndBlock("One Small Step: " .. description,-1); + return "One Small Step: " .. table.concat(description, ", ") end +local function AllowKeyEventNavigation() + return getSetting("AllowKeyEventNavigation") +end -local function deleteMoveBack(take) - local mediaItem = reaper.GetMediaItemTake_Item(take) - local track = reaper.GetMediaItemTake_Track(take) - local note_len = resolveNoteLenQN(take); +-- Commits the currently held notes into the take +local function commit(track, take, notes_to_add, notes_to_extend, triggered_by_key_event) - local cursorTime = reaper.GetCursorPosition() - local cursorQN = reaper.TimeMap2_timeToQN(0, cursorTime) - local rewindTime = reaper.TimeMap2_QNToTime(0, cursorQN - note_len) + local currentop = resolveOperationMode(true) - local cursorPPQ = reaper.MIDI_GetPPQPosFromProjTime(take, cursorTime) - local rewindPPQ = reaper.MIDI_GetPPQPosFromProjTime(take, rewindTime) + local writeModeON = (currentop.mode == "Write") + local navigateModeOn = (currentop.mode == "Navigate") + local insertModeOn = (currentop.mode == "Insert") + local replaceModeOn = (currentop.mode == "Replace") - local shcount = 0 - local remcount = 0 - local mvcount = 0 + if navigateModeOn then + if (not triggered_by_key_event) or AllowKeyEventNavigation() then + return navigateForward(track) + else + -- Triggered by key event and not allowed ... do nothing + return + end + end - reaper.Undo_BeginBlock(); + -- Other operations perform changes so go. + if take == nil then + take = CreateItemIfMissing(track); + end - -- Try to extend existing notes - local torem = {} - local tomove = {} + local note_len = resolveNoteLenQN(take); + local mediaItem = reaper.GetMediaItemTake_Item(take) - local _, notecnt, _, _ = reaper.MIDI_CountEvts(take); + local cursorTime = reaper.GetCursorPosition() + local cursorQN = reaper.TimeMap2_timeToQN(0, cursorTime) + local cursorPPQ = reaper.MIDI_GetPPQPosFromProjTime(take, cursorTime) - local ni = 0; - while (ni < notecnt) do + local advanceQN = cursorQN + note_len; + local advanceTime = reaper.TimeMap2_QNToTime(0, advanceQN) + local advancePPQ = reaper.MIDI_GetPPQPosFromProjTime(take, advanceTime) - -- Examine each note in item - local n = GetNote(take, ni); + local newMaxQN = (justAdvancing and cursorQN) or advanceQN + + local shcount, remcount, mvcount, addcount, extcount = 0, 0, 0, 0, 0 + + local torem = {} + local tomod = {} + local toadd = {} + + local buildNewMidiNote = function(note_from_manager) + return { + index = nil, + selected = getSetting("SelectInputNotes"), + muted = false, + chan = note_from_manager.chan, + pitch = note_from_manager.note, + vel = note_from_manager.velocity, + startPPQ = cursorPPQ, + endPPQ = advancePPQ, + startQN = cursorQN, + endQN = advanceQN + } + end - local startsBetweenRewindAndCursor = (rewindPPQ-1 < n.startPPQ) and (n.startPPQ < cursorPPQ+1) - local endsBetweenRewindAndcursor = (rewindPPQ-1 < n.endPPQ) and (n.endPPQ < cursorPPQ+1) - local endsMatchesCursor = (math.abs(n.endPPQ - cursorPPQ) < 1.0) - local shortenable = endsBetweenRewindAndcursor or endsMatchesCursor - local startsAfterCursor = (cursorPPQ-1 < n.startPPQ) + reaper.Undo_BeginBlock(); - if startsBetweenRewindAndCursor then + -- First, move some notes if insert mode is on + if insertModeOn then + local _, notecnt, _, _ = reaper.MIDI_CountEvts(take) + local ni = 0 - if endsBetweenRewindAndcursor then - torem[#torem+1] = n - else - local startQN = reaper.MIDI_GetProjQNFromPPQPos(take, cursorPPQ) - note_len - local endQN = reaper.MIDI_GetProjQNFromPPQPos(take, n.endPPQ) - note_len + while (ni < notecnt) do + local n = GetNote(take, ni); - n.startPPQ = reaper.MIDI_GetPPQPosFromProjQN(take, startQN) - n.endPPQ = reaper.MIDI_GetPPQPosFromProjQN(take, endQN) + if noteStartsAfterPPQ(n, cursorPPQ, false) then + -- Move the note + setNewNoteBounds(n, take, n.startPPQ, n.endPPQ, note_len, note_len) - tomove[#tomove+1] = n - torem[#torem+1] = n + if n.endQN > newMaxQN then + newMaxQN = n.endQN + end - remcount = remcount + 1 + -- It should be removed and readded, because the start position changes + torem[#torem + 1] = n + toadd[#toadd + 1] = n + + mvcount = mvcount + 1 end - elseif shortenable then + ni = ni + 1 + end + end + + if replaceModeOn then + -- Erase forward + local _, notecnt, _, _ = reaper.MIDI_CountEvts(take); + + local ni = 0; + while (ni < notecnt) do - if rewindPPQ <= (n.startPPQ + 1.0) then - torem[#torem+1] = n - remcount = remcount + 1 + -- Examine each note in item + local n = GetNote(take, ni); + + if noteStartsAfterPPQ(n, advancePPQ, false) then + -- Note is not in the erasing window + -- + -- C A + -- | | + -- | | ==== + -- | | + -- + elseif noteStartsAfterPPQ(n, cursorPPQ, false) then + if noteEndsBeforePPQ(n, advancePPQ, false) then + -- Note should be suppressed + -- + -- C A + -- | | + -- | === | + -- | | + -- + torem[#torem+1] = n + remcount = remcount + 1 + else + -- The note should be shortened (removing tail). + -- Since its start will change, it should be removed and reinserted (see reaper's API doc) + -- + -- RC A + -- | | + -- | ==|=== + -- | | + -- + setNewNoteBounds(n, take, advancePPQ, n.endPPQ, 0, 0) + + torem[#torem+1] = n + toadd[#toadd+1] = n + + shcount = shcount + 1 + mvcount = mvcount + 1 + end else - shcount = shcount + 1 - n.endPPQ = rewindPPQ - SetNote(take, n, true) + if noteEndsAfterPPQ(n, advancePPQ, false) then + -- We should make a hole. Shorten (or erase) left part. Shorten (or erase) right part + -- + -- C A + -- | | + -- ==|=====|=== + -- | | + -- + if noteStartsOnPPQ(n, cursorPPQ) then + -- The start changes, remove and reinsert + setNewNoteBounds(n, take, advancePPQ, n.endPPQ, 0, 0) + + torem[#torem+1] = n + toadd[#toadd+1] = n + + shcount = shcount + 1 + mvcount = mvcount + 1 + else + -- Copy note + local newn = {} + for k,v in pairs(n) do + newn[k] = v + end + + -- Shorten the note + setNewNoteBounds(n, take, n.startPPQ, cursorPPQ, 0, 0) + + tomod[#tomod+1] = n + shcount = shcount + 1 + + if not noteEndsOnPPQ(newn, advancePPQ) then + -- Add new note + setNewNoteBounds(newn, take, advancePPQ, newn.endPPQ, 0, 0); + toadd[#toadd+1] = newn + addcount = addcount + 1 + end + end + + elseif noteEndsAfterPPQ(n, cursorPPQ, true) then + -- Note ending should be erased + -- + -- C A + -- | | + -- ==|=== | + -- | | + -- + setNewNoteBounds(n, take, n.startPPQ, cursorPPQ, 0, 0); + tomod[#tomod+1] = n + shcount = shcount + 1 + else + -- Leave untouched + -- + -- C A + -- | | + -- === | | + -- | | + -- + end + end - elseif startsAfterCursor then - -- Has to be moved. When moving multiple notes at once, they should be removed and re-inserted ... (says the doc) - -- Move back - local startQN = reaper.MIDI_GetProjQNFromPPQPos(take, n.startPPQ) - note_len - local endQN = reaper.MIDI_GetProjQNFromPPQPos(take, n.endPPQ) - note_len + ni = ni + 1; + end - n.startPPQ = reaper.MIDI_GetPPQPosFromProjQN(take, startQN) - n.endPPQ = reaper.MIDI_GetPPQPosFromProjQN(take, endQN) + end - tomove[#tomove+1] = n - torem[#torem+1] = n + -- All modes (Write / Insert / Replace) will insert new notes + for _, v in ipairs(notes_to_add) do + toadd[#toadd+1] = buildNewMidiNote(v) + addcount = addcount + 1 + end + + -- All modes (Write / Insert / Replace) will extend existing notes + if #notes_to_extend > 0 then + local _, notecnt, _, _ = reaper.MIDI_CountEvts(take); - remcount = remcount + 1 + for _, exnote in pairs(notes_to_extend) do + + -- Search for a note that could be extended (matches all conditions) + local ni = 0; + local found = false; + + while (ni < notecnt) do + local n = GetNote(take, ni); + + -- Extend the note if found + if noteEndsOnPPQ(n, cursorPPQ) and (n.chan == exnote.chan) and (n.pitch == exnote.note) then + + tomod[#tomod + 1] = n + setNewNoteBounds(n, take, n.startPPQ, advancePPQ, 0, 0) + + extcount = extcount + 1; + found = true + end + + ni = ni + 1; + end + + if not found then + -- Could not find a note to extend... create one ! + toadd[#toadd+1] = buildNewMidiNote(exnote) + addcount = addcount + 1 + end end + end - ni = ni + 1; + -- Modify notes + for ri = 1, #tomod, 1 do + local n = tomod[ri] + reaper.MIDI_SetNote(take, n.index, nil, nil, n.startPPQ, n.endPPQ, nil, nil, nil, true ) end -- Delete notes that were shorten too much -- Do this in reverse order to be sure that indices are descending for ri = #torem, 1, -1 do - reaper.MIDI_DeleteNote(take, torem[ri].index); + reaper.MIDI_DeleteNote(take, torem[ri].index) end -- Reinsert moved notes - for ri = 1, #tomove, 1 do - local n = tomove[ri] + for ri = 1, #toadd, 1 do + local n = toadd[ri] reaper.MIDI_InsertNote(take, n.selected, n.muted, n.startPPQ, n.endPPQ, n.chan, n.pitch, n.vel, true ) end - -- Rewind and mark dirty - reaper.MIDI_Sort(take); + -- Advance and mark dirty + reaper.MIDI_Sort(take) reaper.UpdateItemInProject(mediaItem) - reaper.SetEditCurPos(rewindTime, false, false); - reaper.MarkTrackItemsDirty(track, mediaItem) + reaper.SetEditCurPos(advanceTime, false, false); + if getSetting("AutoScrollArrangeView") then + KeepEditCursorOnScreen() + end - local description = ""; + -- Grow the midi item if needed + local itemStartTime = reaper.GetMediaItemInfo_Value(mediaItem, "D_POSITION") + local itemLength = reaper.GetMediaItemInfo_Value(mediaItem, "D_LENGTH") + local itemEndTime = itemStartTime + itemLength; + local newMaxTime = reaper.TimeMap2_QNToTime(0, newMaxQN) - if shcount == 0 then - if remcount == 0 then - description = "One Small Step: Stepping back" - else - description = "One Small Step: Removed " .. remcount .. " notes." - end + if(itemEndTime >= newMaxTime) then + -- Cool, the item is big enough else - if remcount == 0 then - description = "One Small Step: Shortened " .. shcount .. " notes." + local itemStartQN = reaper.TimeMap2_timeToQN(0, itemStartTime) + local itemEndQN = reaper.TimeMap2_timeToQN(0, newMaxTime) + + reaper.MIDI_SetItemExtents(mediaItem, itemStartQN, itemEndQN) + reaper.UpdateItemInProject(mediaItem); + end + + -- Mark item as dirty + reaper.MarkTrackItemsDirty(track, mediaItem) + + reaper.Undo_EndBlock(commitDescription(1, addcount, remcount, shcount, extcount, mvcount),-1); +end + +local blockRewindRef = nil + +local function commitBack(track, take, notes_to_shorten, triggered_by_key_event) + + local currentop = resolveOperationMode(true) + + local writeModeON = (currentop.mode == "Write") + local navigateModeOn = (currentop.mode == "Navigate") + local insertModeOn = (currentop.mode == "Insert") + local replaceModeOn = (currentop.mode == "Replace") + + local fullEraseMode = false + + if navigateModeOn or not take then + if triggered_by_key_event and not AllowKeyEventNavigation() then + -- Do nothing, not allowed + return else - description = "One Small Step: Removed " .. remcount .. " notes, and shortened " .. shcount .. " notes." + return navigateBack(track) end end - reaper.Undo_EndBlock("One Small Step: " .. description,-1); -end + if insertModeOn then + fullEraseMode = true --- Commits the currently held notes into the take -local function commitBack(take, notes_to_shorten) + if (#notes_to_shorten > 0) then - local insertModeOn = IsSPInsertModifierKeyPressed() or getInsertBackActionTrigger(); + -- Back + Insert + Selective ?? + -- This is a complicated behavior : we want to erase back, but only some notes + -- For the others what to we do ? move them ? if they're after the cursor ? + -- And if they contain the cursor ? - if insertModeOn then - return deleteMoveBack(take) + -- For now, just force a full erase + notes_to_shorten = {} + end + + if triggered_by_key_event and not AllowKeyEventNavigation() then + -- Don't allow erasing when triggered by key + return + end + end + + if replaceModeOn then + fullEraseMode = true + if #notes_to_shorten > 0 then + -- Ignore selective erasing + notes_to_shorten = {} + end + + if triggered_by_key_event and not AllowKeyEventNavigation() then + -- Don't allow erasing when triggered by key + return + end end local mediaItem = reaper.GetMediaItemTake_Item(take) - local track = reaper.GetMediaItemTake_Track(take) local note_len = resolveNoteLenQN(take); local cursorTime = reaper.GetCursorPosition() + local cursorPPQ = reaper.MIDI_GetPPQPosFromProjTime(take, cursorTime) local cursorQN = reaper.TimeMap2_timeToQN(0, cursorTime) + + local itemStartTime = reaper.GetMediaItemInfo_Value(mediaItem, "D_POSITION") + local itemStartPPQ = reaper.MIDI_GetPPQPosFromProjTime(take, itemStartTime) + local rewindTime = reaper.TimeMap2_QNToTime(0, cursorQN - note_len) - local cursorPPQ = reaper.MIDI_GetPPQPosFromProjTime(take, cursorTime) + if rewindTime < itemStartTime then + rewindTime = itemStartTime + end + local rewindPPQ = reaper.MIDI_GetPPQPosFromProjTime(take, rewindTime) - local shcount = 0; - local remcount = 0 + -- If we're at the start of an item don't move things + if math.abs(itemStartPPQ - cursorPPQ) < PPQ_TOLERANCE then + return + end + + local shcount, remcount, mvcount, addcount, extcount = 0, 0, 0, 0, 0 reaper.Undo_BeginBlock(); -- Try to extend existing notes - local torem = {} - if #notes_to_shorten > 0 then - local _, notecnt, _, _ = reaper.MIDI_CountEvts(take); + local torem = {} + local tomod = {} + local toadd = {} - local ni = 0; - while (ni < notecnt) do + local _, notecnt, _, _ = reaper.MIDI_CountEvts(take); - -- Examine each note in item - local _, _, _, startPPQ, endPPQ, chan, pitch, _ = reaper.MIDI_GetNote(take, ni); + local ni = 0; + while (ni < notecnt) do - -- Compare to what we have in our shorten list - for _, shnote in pairs(notes_to_shorten) do + -- Examine each note in item + local n = GetNote(take, ni); - local endsMatchesCursor = (math.abs(endPPQ - cursorPPQ) < 1.0) - local endsBetweenRewindAndcursor = (rewindPPQ < endPPQ) and (endPPQ < cursorPPQ) - local shortenable = endsMatchesCursor or (getSetting("AllowErasingWhenNoteEndDoesNotMatchCursor") and endsBetweenRewindAndcursor); + local targetable = false - if shortenable and chan == shnote.chan and pitch == shnote.note then - if rewindPPQ <= (startPPQ + 1.0) then - torem[#torem+1] = ni; - remcount = remcount + 1 + if fullEraseMode then + -- steping back with insert mode on makes all notes potentially targetable + targetable = true + else + for _, shnote in pairs(notes_to_shorten) do + if n.chan == shnote.chan and n.pitch == shnote.note then + targetable = true + break + end + end + end + + if targetable then + if noteStartsAfterPPQ(n, cursorPPQ, false) then + -- Note should be moved back or left untouched (if in cursor mode or not) + -- + -- R C + -- | | + -- | | ==== + -- | | + -- + if insertModeOn then + -- Move the note back + setNewNoteBounds(n, take, n.startPPQ, n.endPPQ, -note_len, -note_len) + + torem[#torem+1] = n -- Remove + toadd[#toadd+1] = n -- And readd + + mvcount = mvcount + 1 + end + elseif noteStartsAfterPPQ(n, rewindPPQ, false) then + if noteEndsBeforePPQ(n, cursorPPQ, false) then + -- Note should be suppressed + -- + -- R C + -- | | + -- | === | + -- | | + -- + torem[#torem+1] = n + remcount = remcount + 1 + else + -- The note should be shortened (removing tail). + -- Since its start will change, it should be removed and reinserted (see reaper's API doc) + -- + -- R C + -- | | + -- | ==|=== + -- | | + -- + local offset = (insertModeOn) and (-note_len) or (0) + setNewNoteBounds(n, take, cursorPPQ, n.endPPQ, offset, offset) + + torem[#torem+1] = n + toadd[#toadd+1] = n + + shcount = shcount + 1 + mvcount = mvcount + 1 + end + else + if noteEndsAfterPPQ(n, cursorPPQ, false) then + -- Note should be cut. + -- + -- R C + -- | | + -- ==|=====|=== + -- | | + -- + if insertModeOn or noteEndsOnPPQ(n, cursorPPQ) then + setNewNoteBounds(n, take, n.startPPQ, n.endPPQ, 0, -note_len) + + tomod[#tomod+1] = n + shcount = shcount + 1 else - shcount = shcount + 1 + -- Create a hole in the note. Copy note + local newn = {} + for k,v in pairs(n) do + newn[k] = v + end + + -- Shorted remaining note + setNewNoteBounds(n, take, n.startPPQ, rewindPPQ, 0, 0); + tomod[#tomod+1] = n + shcount = shcount + 1 + + -- Add new note + setNewNoteBounds(newn, take, cursorPPQ, newn.endPPQ, 0, 0); + toadd[#toadd+1] = newn + addcount = addcount + 1 end - reaper.MIDI_SetNote(take, ni, nil, nil, nil, rewindPPQ, nil, nil, nil, true); + elseif noteEndsAfterPPQ(n, rewindPPQ, true) then + -- Note ending should be erased + -- + -- R C + -- | | + -- ==|=== | + -- | | + -- + setNewNoteBounds(n, take, n.startPPQ, rewindPPQ, 0, 0); + tomod[#tomod+1] = n + shcount = shcount + 1 + else + -- Leave untouched + -- + -- R C + -- | | + -- === | | + -- | | + -- end end - - ni = ni + 1; end + + ni = ni + 1; + end + + -- Modify notes + for ri = 1, #tomod, 1 do + local n = tomod[ri] + reaper.MIDI_SetNote(take, n.index, nil, nil, n.startPPQ, n.endPPQ, nil, nil, nil, true ) end -- Delete notes that were shorten too much -- Do this in reverse order to be sure that indices are descending for ri = #torem, 1, -1 do - reaper.MIDI_DeleteNote(take, torem[ri]); + reaper.MIDI_DeleteNote(take, torem[ri].index) + end + + -- Reinsert moved notes + for ri = 1, #toadd, 1 do + local n = toadd[ri] + reaper.MIDI_InsertNote(take, n.selected, n.muted, n.startPPQ, n.endPPQ, n.chan, n.pitch, n.vel, true ) end -- Rewind and mark dirty reaper.MIDI_Sort(take); reaper.UpdateItemInProject(mediaItem) - reaper.SetEditCurPos(rewindTime, false, false); reaper.MarkTrackItemsDirty(track, mediaItem) - local description = ""; + local blockRewind = false - if shcount == 0 then - if remcount == 0 then - description = "One Small Step: Stepping back" - else - description = "One Small Step: Removed " .. remcount .. " notes." - end + if writeModeON then + -- We block the rewind in certain conditions (when erasing failed, and when during this pedal session, the erasing was blocked) + local pedalStart = currentKeyEventManager():keyActivityForTrack(track).pedal.first_ts + local hadCandidates = (#notes_to_shorten > 0) + local failedToErase = (hadCandidates and (shcount+remcount == 0)) + + blockRewind = (getSetting("DoNotRewindOnStepBackIfNothingErased") and failedToErase) or ((not hadCandidates) and (pedalStart == blockRewindRef)) + end + + if blockRewind then + blockRewindRef = pedalStart else - if remcount == 0 then - description = "One Small Step: Shortened " .. shcount .. " notes." - else - description = "One Small Step: Removed " .. remcount .. " notes, and shortened " .. shcount .. " notes." + if fullEraseMode or (not hadCandidates) or (not nothingWasErased) then + reaper.SetEditCurPos(rewindTime, false, false); + if getSetting("AutoScrollArrangeView") then + KeepEditCursorOnScreen() + end end end - reaper.Undo_EndBlock("One Small Step: " .. description,-1); + reaper.Undo_EndBlock(commitDescription(-1, addcount, remcount, shcount, extcount, mvcount),-1); end +local function hasTrigger(forward) + local res = false + for k,v in pairs(ActionTriggers) do + local cond = false + if forward then + cond = not v.back + else + cond = v.back + end + if cond then + res = (res or getActionTrigger(k)) + end + end + return res +end -- Listen to events from instrumented tracks that have the JSFX companion effect installed (or install it if not present) local function listenToEvents() @@ -1048,72 +1762,50 @@ local function listenToEvents() local oss_state = helper_lib.oneSmallStepState(track); - -- We have different managers for all modes - -- But their architecture is identical and compliant - if mode == InputMode.KeyboardPress then - manager = KPActivityManager; - elseif mode == InputMode.KeyboardRelease then - manager = KRActivityManager; - else - manager = APActivityManager; - end + -- Get the manager for the current input mode + local manager = currentKeyEventManager(); -- Update manager with new info from the helper JSFX manager:updateActivity(track, oss_state); - local spmod = IsSPStepBackModifierKeyPressed(); - local pedal = manager:pullPedalTriggerForTrack(track); - local preventcommitwhenspmod = getSetting("PreventAddingNotesIfModifierKeyIsPressed"); - - -- Try to commit with advanced behaviours (key press, key release) - manager:tryAdvancedCommitForTrack(track, function(candidates, held_candidates) - -- The next condition is used specifically to prevent notes - -- From being added in KeyboardPress mode when the modifier key is down - -- This is going to happen when a user wants to step back - -- and first presses the key of the note to erase ... - -- Without this condition this would first re-add the note in question - if (not spmod) or (spmod and not preventcommitwhenspmod) then - if take == nil and #candidates > 0 then - take = CreateItemIfMissing(track); + local spmod = IsStepBackModifierKeyPressed(); + local pedal = manager:pullPedalTriggerForTrack(track); + + manager:tryAdvancedCommitForTrack(track, + function(candidates, held_candidates) + -- The advanced commit is dedicated to key event(s) triggerering + if not spmod then + -- Advance + commit(track, take, candidates, held_candidates, true) + else + -- If going back all held notes are candidates for selective removal + -- So concatenate + for i=1,#held_candidates do + candidates[#candidates+1] = held_candidates[i] end - commit(take, candidates, held_candidates); + commitBack(track, take, candidates, true) end end ); -- Allow the use of the action or pedal - if (pedal and not spmod) or getCommitActionTrigger() or getInsertActionTrigger() then - manager:simpleCommit(track, function(commit_candidates, extend_candidates) - if take == nil then - -- The condition is very large, because it may be a rest insertion - take = CreateItemIfMissing(track); - end - commit(take, commit_candidates, extend_candidates); + if (pedal and not spmod) or hasTrigger(true) then + manager:simpleCommit(track, function(commit_candidates, held_candidates) + commit(track, take, commit_candidates, held_candidates, false); end ); - - clearCommitActionTrigger() - clearInsertActionTrigger() end - if (pedal and spmod) or getCommitBackActionTrigger() or getInsertBackActionTrigger() then + if (pedal and spmod) or hasTrigger(false) then manager:simpleCommitBack(track, function(shorten_candidates) - if (take == nil) then - justStepBack(); - else - commitBack(take, shorten_candidates) - end + commitBack(track, take, shorten_candidates, false) end ); - - clearCommitBackActionTrigger() - clearInsertBackActionTrigger() end - manager:clearOutdatedActivity() - -- Clear Insert action triggers + manager:clearOutdatedActivity() - clearInsertBackActionTrigger() + clearAllActionTriggers() if getSetting("PedalRepeatEnabled") then manager:forgetPedalTriggerForTrack(track, getSetting("PedalRepeatTime"), getSetting("PedalRepeatFirstHitMultiplier")) @@ -1121,17 +1813,8 @@ local function listenToEvents() end -- To be called from companion action script -function reaperActionCommit() - setCommitActionTrigger(); -end -function reaperActionCommitBack() - setCommitBackActionTrigger() -end -function reaperActionInsert() - setInsertActionTrigger() -end -function reaperActionInsertBack() - setInsertBackActionTrigger() +function reaperAction(action_name) + setActionTrigger(action_name) end function cleanupCompanionFXs() @@ -1180,12 +1863,8 @@ function atStart() -- Then we can uncomment this automatic cleanup -- cleanupCompanionFXs(); - clearCommitActionTrigger() - clearInsertActionTrigger() - clearCommitBackActionTrigger() - clearInsertBackActionTrigger() - - mayRestorePlaybackMarkerOnStart(); + clearAllActionTriggers() + mayRestorePlaybackMarkerOnStart() end function atExit() @@ -1204,23 +1883,22 @@ end EngineLib = { - IsSPStepBackModifierKeyPressed = IsSPStepBackModifierKeyPressed, - IsSPInsertModifierKeyPressed = IsSPInsertModifierKeyPressed, + IsStepBackModifierKeyPressed = IsStepBackModifierKeyPressed, + resolveOperationMode = resolveOperationMode, -- Enums InputMode = InputMode, + EditMode = EditMode, NoteLenParamSource = NoteLenParamSource, NoteLenModifier = NoteLenModifier, ModifierKeys = ModifierKeys, ModifierKeyLookup = ModifierKeyLookup, - getSPStepBackModifierKey = getSPStepBackModifierKey, - getSPInsertModifierKey = getSPInsertModifierKey, + ModifierKeyCombinations = ModifierKeyCombinations, + ModifierKeyCombinationLookup = ModifierKeyCombinationLookup, NoteLenDefs = NoteLenDefs, - AugmentedDiminishedDefs = AugmentedDiminishedDefs, - --Functions setInputMode = setInputMode, getInputMode = getInputMode, @@ -1233,12 +1911,6 @@ EngineLib = { setTupletDivision = setTupletDivision, getTupletDivision = getTupletDivision, - getNoteADFactor = getNoteADFactor, - setNoteADFactor = setNoteADFactor, - - getNoteADSign = getNoteADSign, - setNoteADSign = setNoteADSign, - getNoteLenModifier = getNoteLenModifier, setNoteLenModifier = setNoteLenModifier, getNoteLenModifierFactor = getNoteLenModifierFactor, @@ -1262,10 +1934,7 @@ EngineLib = { resetSetting = resetSetting, getSettingSpec = getSettingSpec, - reaperActionCommit = reaperActionCommit, - reaperActionCommitBack = reaperActionCommitBack, - reaperActionInsert = reaperActionInsert, - reaperActionInsertBack = reaperActionInsertBack, + reaperAction = reaperAction, TakeForEdition = TakeForEdition, TrackForEditionIfNoItemFound = TrackForEditionIfNoItemFound, diff --git a/MIDI Editor/talagan_OneSmallStep/classes/helper_lib.lua b/MIDI Editor/talagan_OneSmallStep/classes/helper_lib.lua index 692b387a8..90335ddfe 100644 --- a/MIDI Editor/talagan_OneSmallStep/classes/helper_lib.lua +++ b/MIDI Editor/talagan_OneSmallStep/classes/helper_lib.lua @@ -33,7 +33,7 @@ local function getOrAddInputFx(track, fx) reaper.Undo_EndBlock("One Small Step : Add companion JSFX on track " .. tname,-1); return -1; else - -- It worked, hide it ide it, in case the option to pop up new added FXs is checked + -- It worked, hide it in case the option to pop up new added FXs is checked reaper.TrackFX_SetOpen(track, idx|0x1000000, false); reaper.Undo_EndBlock("One Small Step : Add companion JSFX on track " .. tname,-1); end diff --git a/MIDI Editor/talagan_OneSmallStep/images/edit_mode_insert.lua b/MIDI Editor/talagan_OneSmallStep/images/edit_mode_insert.lua new file mode 100644 index 000000000..146bddeb9 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/edit_mode_insert.lua @@ -0,0 +1,13 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x00\x84\x49\x44\x41\x54\x38\x8D\xBD\x94\xE1\x0E\x80\x20\x08\x84\x3D\xD7\xFB\xBF\x32\xFD\x92\xF0\z +\x42\x87\x62\xDD\xD6\x0C\x94\x2F\x05\x0C\x22\x52\x4E\xEA\x22\x7B\x97\x8E\xF6\x52\x0F\xC0\xBA\xD8\xCA\x8E\x2C\x94\x8F\x0C\x5E\xB0\xAA\x4A\xB6\xD0\x98\x06\xA6\xF5\z +\x3B\x10\x66\x84\x33\xF7\xF2\x47\x76\x88\xF2\xE4\x14\xE4\x6B\x8F\xDB\x87\x23\x45\x0A\xA5\x73\xDC\x36\x51\x75\xBB\x3A\x01\xEC\x20\xC5\xA4\x65\xB7\xCA\x5C\x20\xD5\z +\xE8\xA6\xD8\x42\x78\x0A\x1F\x99\x21\x33\xDB\xFD\xE0\x67\x8D\x3D\xCC\xC9\x82\x60\x81\x59\xA8\xC6\xCE\x7E\x5F\x5B\xBA\x01\xAB\x9E\x1D\x30\x13\x6F\x62\xF9\x00\x00\z +\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/edit_mode_navigate.lua b/MIDI Editor/talagan_OneSmallStep/images/edit_mode_navigate.lua new file mode 100644 index 000000000..f067de725 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/edit_mode_navigate.lua @@ -0,0 +1,13 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x00\x7D\x49\x44\x41\x54\x38\x8D\xCD\x94\xDB\x0A\xC0\x20\x0C\x43\x57\xFF\xFF\x9F\xBB\xA7\x81\xB6\z +\x49\xD6\x8A\xB0\x05\x04\xED\xE5\x50\xB5\x6A\xEE\x7E\x9D\xD4\x38\x4A\xFB\x0A\xE8\x64\xBE\x05\x44\x00\x09\x55\x40\x95\x48\x7D\x0C\xF8\x24\xD8\xB4\x46\xB6\x24\x03\z +\x6D\x13\x13\x99\x60\x5C\xAC\xB0\x0A\x9B\x63\x96\x8A\x66\x60\x07\x46\xA1\x43\x39\x0B\x4A\x45\xC4\x2D\x77\xA0\xA5\x33\x44\x50\x0F\x83\xC2\x18\x10\x41\x8D\xD8\x92\z +\x54\x63\xAB\xCB\xA1\xBE\xB7\xA7\x87\x12\x65\x17\x54\x3E\x07\x23\xF3\x6D\x60\x4B\xFF\x07\xDE\x7D\x37\x22\x1D\xC3\x9E\xA7\xEB\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\z +\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/edit_mode_replace.lua b/MIDI Editor/talagan_OneSmallStep/images/edit_mode_replace.lua new file mode 100644 index 000000000..d564f30e3 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/edit_mode_replace.lua @@ -0,0 +1,13 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x00\x7F\x49\x44\x41\x54\x38\x8D\xCD\x54\x41\x0E\xC0\x20\x08\xA3\x8B\xFF\xFF\x32\xBB\x8C\x04\x5D\z +\x45\x31\x64\x19\x97\x02\x26\xB5\x14\x23\x54\x55\x2A\xA3\x3D\x58\xC5\x0A\x23\x44\x11\xA1\x5C\x55\x44\x16\xCD\xE5\x6C\xEC\xB4\x72\xAF\x10\x0E\x2D\x4F\x7B\x1B\x8D\z +\x7C\xE4\x6B\xB9\x87\x11\xE1\xD1\x53\x6A\xA4\xE7\x89\x10\xF4\xC7\x0B\x21\xC2\x15\x62\x40\x76\xE6\xEB\xAE\x37\x1B\x99\x29\xD8\x8A\xEC\x52\x74\x54\x94\x21\x9C\xFA\z +\xB4\x4B\xA8\x0B\xB4\x3C\xAA\xBB\x2D\x33\xC3\x57\xEA\x5E\xBD\x4F\x1F\xF6\x2A\xA8\x9F\xFF\xFF\x60\x6F\xA3\x4F\x16\x3A\x4F\x1B\x90\xCA\x00\x00\x00\x00\x49\x45\x4E\z +\x44\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/edit_mode_write.lua b/MIDI Editor/talagan_OneSmallStep/images/edit_mode_write.lua new file mode 100644 index 000000000..9ad4a8a80 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/edit_mode_write.lua @@ -0,0 +1,12 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x00\x5D\x49\x44\x41\x54\x38\x8D\xED\x93\x4B\x0E\x00\x10\x0C\x44\x55\xDC\xFF\xCA\x63\x61\x23\x55\z +\xFD\x48\x13\x16\xDE\xD6\x78\xA9\x49\x11\x80\x92\x49\x4D\xB5\x7D\x61\x0A\xCD\x99\xD3\x56\x81\x4E\x84\x64\x47\x06\xD7\x9E\xCC\x91\x2A\x20\x4D\x08\x1E\x94\x2E\x4B\z +\xEC\x84\xEE\xCE\xBC\xC2\x19\x6B\xDA\xB0\x30\x34\xED\x2C\xE4\x45\x4B\x22\x28\x67\x8B\xD0\x33\x89\x99\x79\xFF\x2F\xBF\x2F\xEC\x3B\xD9\x09\x3D\x5B\xDD\x05\x09\x00\z +\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/frac_1.lua b/MIDI Editor/talagan_OneSmallStep/images/frac_1.lua new file mode 100644 index 000000000..782aedd1b --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/frac_1.lua @@ -0,0 +1,11 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x00\x44\x49\x44\x41\x54\x38\x8D\xED\xD4\xB1\x0D\x00\x20\x08\x44\xD1\xAF\xB3\xE1\xD6\xAE\xE2\x2C\z +\x67\x69\x29\x24\xC4\x46\x7E\x72\x1D\x79\x25\x4D\x12\x99\xF5\x54\xAD\xC0\x67\xA0\x01\x02\x56\x16\x38\x81\xE1\xC1\xBC\x60\xA8\x0F\x41\x24\xDD\x66\x3A\xAD\xDB\x7D\z +\xAB\xE7\x50\x60\xBC\x0D\x63\x99\x48\x23\xF0\x2F\x34\x68\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/frac_1_16.lua b/MIDI Editor/talagan_OneSmallStep/images/frac_1_16.lua new file mode 100644 index 000000000..9757afea4 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/frac_1_16.lua @@ -0,0 +1,14 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x00\xB6\x49\x44\x41\x54\x38\x8D\xCD\x94\xD1\x0D\xC2\x30\x0C\x44\x5F\x10\x0B\x64\x05\x56\x60\x17\z +\x46\xC8\x2C\xAC\x40\x47\x80\x11\x58\xA1\x8C\xC0\x0C\x1D\xE1\xF8\xC0\xA5\x15\x24\xAD\x43\x2B\xC4\x49\xFE\x88\x93\x3C\xDB\xD1\x29\x41\x12\x6B\x6A\xB3\x2A\xED\x97\z +\xC0\x04\x08\x38\xD5\x02\xB7\x85\x7C\x03\x44\x60\x37\x73\x5F\x40\x18\x27\x96\x8C\xFC\x01\x5B\x02\xCC\xC2\xBE\x05\x16\x61\xCF\x5D\x29\x17\x49\x83\xD2\x28\xAF\xC2\z +\xF9\x57\x84\x0A\x63\x4F\x77\x66\xF2\x8E\xEC\x82\x79\x81\x3D\x2C\xE7\xCD\x08\x9C\x81\x16\xD8\x43\xD9\x87\xB9\xCE\xDE\xBD\x19\x0D\xD4\x00\x07\x4F\x87\x73\x63\x26\z +\x83\x1F\x81\x7B\x5F\xA8\x04\xF4\xBE\xD9\xC5\xCE\xDD\xAC\x40\x16\xE8\x85\x75\x0C\xE3\x77\x16\x45\x1F\x7A\xBD\x79\xB5\x75\x2B\x29\xD6\xFA\xD0\xA5\xFF\xFF\x60\x1F\z +\x60\x4F\xA4\xC9\xAE\x3A\xF0\xA9\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/frac_1_2.lua b/MIDI Editor/talagan_OneSmallStep/images/frac_1_2.lua new file mode 100644 index 000000000..455c5cb4f --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/frac_1_2.lua @@ -0,0 +1,14 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x00\xB4\x49\x44\x41\x54\x38\x8D\xCD\x94\xE1\x0D\xC2\x20\x10\x46\x1F\xC6\x05\x58\xA1\x2B\x74\x05\z +\x57\x70\x05\x9C\x49\x46\x70\x16\x67\x70\x04\x1D\xE1\xF3\x87\x54\x49\x0B\x05\xA4\x31\x5E\x72\x81\x1C\xDC\xCB\x1D\x7C\x60\x24\xB1\xA5\xED\x36\xA5\xFD\x12\xE8\x00\z +\x01\xE7\x56\xE0\x3E\x13\xF7\x80\x05\x86\x42\xBE\x00\x13\x07\x7A\x5A\x5E\xC0\x7A\x80\x49\xD8\xB7\xC0\x2C\xEC\xB5\x2A\xA5\xDC\xE9\x63\x2E\x8A\x2B\xB3\xFF\xED\xA6\z +\x41\xD8\xEB\x95\x05\xAB\x6D\xB9\x0A\x56\x0B\x9C\xC3\x26\x8D\x0A\x38\xB4\x02\x53\x95\x8D\x21\xE6\x81\xE3\x3C\x21\x27\xEC\x1C\x0C\xE0\x14\xC6\x1B\xF0\xA8\xAD\xB0\z +\x74\x66\xD3\x0B\xF2\xCB\xCC\xE5\xD5\x97\xA4\x31\x48\xBA\x84\xF9\x28\xC9\xC6\xEB\xAB\x9A\x4A\xB8\x95\x74\x8F\x34\x7A\xED\xD1\x61\x95\xFD\xFF\x07\xFB\x04\xEF\xCF\z +\xD9\x8E\x1B\x1F\xC5\x70\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/frac_1_4.lua b/MIDI Editor/talagan_OneSmallStep/images/frac_1_4.lua new file mode 100644 index 000000000..b0c1ab1b8 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/frac_1_4.lua @@ -0,0 +1,13 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x00\x9E\x49\x44\x41\x54\x38\x8D\xCD\x94\xD1\x0D\xC2\x30\x0C\x44\x5F\x10\x0B\x74\x85\xCC\xD2\x59\z +\xD2\x55\x58\xA1\xEC\xD6\x59\x8E\x8F\x56\x34\x50\xBB\x38\xB4\x42\x9C\xE4\x9F\x8B\xFD\x12\xCB\x56\x92\x24\xCE\xD4\xE5\x54\xDA\x2F\x81\x05\x10\x30\xB6\x02\xAF\x8E\z +\x7F\x07\x3A\x20\x7F\xA8\x17\x90\x6A\xE3\x48\xCB\x1B\xD8\x11\xA0\x09\xFB\x16\xE8\xC2\xE6\x53\xC9\x8A\xA2\x55\xA5\xF2\xE5\xE4\x3F\x23\x35\x2C\xF6\xFE\xCB\x16\x45\z +\x5B\x0E\xC1\xA2\x40\x0B\x96\x81\x09\xE8\x5B\x81\x16\xAC\x03\x6E\x5E\xC1\x1E\xD0\x6B\x73\x04\x06\xBF\xCA\x9E\x96\x37\xCD\x5E\x5B\xE5\x3A\xA7\x05\xF6\x1E\xD3\x72\z +\xC1\x8B\x6F\xB5\x1C\x9A\xA6\xA7\x96\x3D\x0C\xE9\xFF\x3F\xD8\x07\xBD\x92\xD6\x57\x1C\x3E\x0A\x78\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/frac_1_8.lua b/MIDI Editor/talagan_OneSmallStep/images/frac_1_8.lua new file mode 100644 index 000000000..f2223b398 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/frac_1_8.lua @@ -0,0 +1,14 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x00\xBC\x49\x44\x41\x54\x38\x8D\xCD\x94\xE1\x0D\xC2\x20\x14\x84\xBF\x1A\x17\x70\x05\x1C\xC1\x15\z +\xEA\x0A\x8E\xC0\x0A\x38\x82\x2B\xE8\x08\xCE\xE0\x08\xAE\xE0\x2C\xE7\x0F\x88\xB6\xB5\xAF\x50\x69\x8C\x97\xBC\x90\x3C\xCA\x17\x0E\xAE\x34\x92\x58\x52\xAB\x45\x69\z +\xBF\x04\x7A\x40\xC0\x79\x2E\x70\x6D\xF4\x2F\xC0\x06\x70\x99\xF5\x02\x9A\x6E\xA3\xC6\xF2\x07\xAC\x06\x38\x0A\xFB\x16\x68\xC2\xE2\xAC\x34\x56\x5E\x6F\xF9\x4E\x5F\z +\xC6\xF7\xAF\x6A\x66\x04\x7B\x7A\x67\x49\xA5\x96\x8B\x60\xA5\xC0\x21\x2C\xA4\x9E\x88\x79\xED\x29\x67\x79\x6C\x67\x0F\xE0\x48\xCC\xE8\x0E\x38\xF4\x57\xD8\x07\x6C\z +\x5D\x40\x2B\xE9\x2E\xE9\x2A\xC9\x0D\xE7\x2D\xCB\x53\x67\xE6\x80\x5B\x1A\xDB\x12\xCB\xB9\x0B\x10\xB0\x27\xFE\x9A\x27\x60\x5B\x6A\xD9\xAA\xD0\xC9\x68\xA8\xC9\x61\z +\x91\xFE\xFF\x81\x7D\x02\x1D\x20\xE0\xD7\xB2\xA1\xE2\xB7\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/frac_1_n.lua b/MIDI Editor/talagan_OneSmallStep/images/frac_1_n.lua new file mode 100644 index 000000000..d6b30b1f9 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/frac_1_n.lua @@ -0,0 +1,14 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x00\xB6\x49\x44\x41\x54\x38\x8D\xE5\x94\xDB\x0D\xC2\x30\x0C\x45\x4F\x10\x0B\xB0\x42\x57\x60\x85\z +\xCE\x92\x15\xCA\x0A\x8C\x00\x23\x94\x11\x58\x01\x56\x60\x04\x56\xB8\x7C\xD4\x82\xD2\xC6\x21\xA5\x15\x3F\x58\xB2\x62\xD9\xF1\x91\xED\x3C\x82\x24\x96\x94\xD5\xA2\z +\xB4\x5F\x02\x23\x20\xE0\x30\x15\xB8\x76\xFC\x47\x60\x03\x54\x1F\xF2\x05\x84\xBE\x63\x4E\xCB\x23\xD8\x1C\x60\x12\xF6\x2D\xD0\x85\x75\x51\x29\xA5\x51\x2F\x89\x3D\z +\xBF\x9C\xFD\x4F\x0D\x13\x2E\x76\xBE\x32\x93\xD2\x96\x8B\x60\xA5\xC0\x62\x58\x09\x70\x08\x6B\xCC\x77\x06\x2E\x40\x3B\xCE\xF0\x07\xEC\x1D\xC0\xDD\x62\x8D\xA4\x76\z +\x18\xF7\x2A\xF4\xDA\xDC\xD2\xBD\xA0\x9D\xAD\xD7\x92\x96\x73\x33\xAB\x81\x1B\xB0\x37\x7B\x24\x29\x60\xEE\x00\x6A\xE0\x64\x76\x65\x55\xBE\x27\xFF\xDF\x07\xFB\x00\z +\xF5\x18\x9D\x97\x13\x1B\x92\x13\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/frac_2.lua b/MIDI Editor/talagan_OneSmallStep/images/frac_2.lua new file mode 100644 index 000000000..98701fd86 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/frac_2.lua @@ -0,0 +1,13 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x00\x7E\x49\x44\x41\x54\x38\x8D\xED\x93\xC1\x09\xC3\x30\x10\x04\x47\xE9\x40\x29\xC1\xB5\xB8\x05\z +\xB7\x90\x16\x52\x4B\x5C\x82\x5B\x48\x4F\x6E\x61\xFC\x70\x1E\x79\xDD\x49\x60\xFC\x30\x5E\x10\x42\x30\x0C\xE2\x56\x2A\x2A\x47\xE6\x71\xA8\xED\x16\x9E\x26\x1C\x81\z +\x15\x10\x78\xA7\xB4\x9A\xAD\x8F\x5A\xD5\xC9\x3D\x35\xE2\x4B\xE7\x3B\x5C\x81\x67\x04\xF4\x08\x5F\xBF\x7D\x8E\xA0\xD6\x52\x06\xA0\x66\x32\xA0\x69\x86\x83\xBA\xFC\z +\x9D\xC7\x88\xCF\x6E\x58\x81\x2F\x30\xB1\xB7\x9C\xCE\xA7\xB7\x94\x34\xD7\xF8\x29\xB7\x30\xCE\x06\x06\x79\x8F\x50\x06\x2A\xD0\x8D\x00\x00\x00\x00\x49\x45\x4E\x44\z +\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/frac_2_3.lua b/MIDI Editor/talagan_OneSmallStep/images/frac_2_3.lua new file mode 100644 index 000000000..413d94fbf --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/frac_2_3.lua @@ -0,0 +1,14 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x00\xBF\x49\x44\x41\x54\x38\x8D\xCD\x94\xE1\x0D\xC2\x20\x10\x85\x1F\xC6\x05\x58\xA1\x2B\x74\x05\z +\x57\x70\x85\x3A\x82\xBB\x74\x84\xBA\x4A\x67\x70\x04\x1D\xE1\xF3\x47\xCF\x48\x5A\xC0\xD3\x10\xE3\x25\x17\x9A\x1E\x7C\xE1\x78\x0F\x02\xA0\x96\xB1\x6B\x4A\xFB\x25\z +\x70\x90\x84\xE5\xA1\x05\xB0\x97\x14\x24\x8D\x92\x8E\x95\xF5\x1B\x01\xF6\x85\x89\x27\x1B\xAF\x92\xEE\x15\x58\xF0\xEE\x50\x92\x3A\x1B\x47\x2F\x6C\xA9\x40\x2E\x3B\z +\x60\xB2\xEF\x1E\x88\x49\x8D\xC2\x1A\x01\x59\x60\x04\x6E\xBC\x62\xF6\xC2\x00\x85\x0F\x8C\x5D\x6E\x33\x09\xAF\x0F\x5D\x30\x2F\x70\x0D\x4B\x3D\xBA\xB1\xD4\x3B\x60\z +\x6E\x67\xD1\xFE\x5D\x94\xB3\x54\xE5\x80\x6B\x02\x4C\x56\x1F\x3C\x2A\xBB\xD4\x04\xCE\x2B\x07\x08\xC8\xB6\xEC\x16\x40\xCB\x4D\x72\xB7\x5C\xCA\xA7\x47\x67\xBB\x00\z +\x5F\xFB\xD0\x15\xFF\xFF\xC0\x3E\x00\x78\x86\x56\xF7\xB9\x61\x47\x9F\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/frac_3_2.lua b/MIDI Editor/talagan_OneSmallStep/images/frac_3_2.lua new file mode 100644 index 000000000..0aea3b0f6 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/frac_3_2.lua @@ -0,0 +1,14 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x00\xBA\x49\x44\x41\x54\x38\x8D\xCD\x94\xE1\x0D\xC2\x20\x14\x84\x0F\xE3\x02\xAC\xC0\x0A\x5D\xC1\z +\x15\x5C\xA1\x8E\xE0\x2E\x1D\x41\x57\xE9\x0C\x1D\x41\x47\xF8\xFC\xE1\x6B\xD2\xB4\x80\x0F\xD3\x18\x5F\x72\x21\x81\xF0\x71\xC0\x41\x00\xB4\x67\x1D\x76\xA5\xFD\x12\z +\xD8\x4B\xC2\x74\xDE\x03\x18\x25\x05\x49\x77\x49\xCF\xCA\xFC\xED\x05\x00\x25\xDD\x78\x57\x5F\x18\x27\xD7\x5F\x03\x0A\xB8\x02\xA3\x17\x06\xB8\x2E\x65\xCA\x6C\x33\z +\x94\x0F\x21\xBF\xD2\xC3\x5C\x8C\x40\xF2\x38\x9B\x15\x1A\x82\x5D\x77\x66\xE5\xCD\xA1\x0B\xE6\x05\xAE\x61\xCB\x8C\x9E\x5A\x81\x39\x67\x9D\xF5\x0D\xCA\x84\xFE\xD8\z +\x08\x93\xA4\x8B\xB5\x93\x32\xA1\x2F\x39\xFC\x74\x66\xC9\xDA\x61\x3B\xB3\x21\xB4\xA6\x64\xAF\x48\x40\x07\xC4\x96\x97\xB2\x56\x5C\x64\x74\xCE\xE9\xD7\x39\x74\xD5\z +\xFF\x7F\xB0\x2F\x5D\xE7\x56\xF7\x3A\x19\x2A\x1E\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/frac_4.lua b/MIDI Editor/talagan_OneSmallStep/images/frac_4.lua new file mode 100644 index 000000000..2d8a03686 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/frac_4.lua @@ -0,0 +1,12 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x00\x63\x49\x44\x41\x54\x38\x8D\x63\xFC\xFF\xFF\x3F\x03\x35\x01\x13\x55\x4D\x1B\x35\x90\xEE\x06\z +\x76\x30\x30\x30\xCC\xA4\x96\x81\xA1\x0C\x0C\x0C\x2E\xC4\x28\x24\xC6\x40\x25\x28\x5E\x4D\x0D\x03\x05\x19\x20\x5E\xED\x24\xC6\x30\x06\x06\x06\x06\x86\xFF\xFF\xFF\z +\xE3\xC3\x2E\xFF\x31\xC1\x4C\x7C\x7A\x18\x49\xC8\x7A\xE5\x0C\x10\xAF\xA7\xE3\x53\x44\xF5\x64\x43\x8A\x0B\x89\x02\xC3\x2B\xA7\x8C\x1A\x88\x1D\x00\x00\xC7\x58\x4E\z +\x83\x1A\xAC\x9B\xEF\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/indicator_insert.lua b/MIDI Editor/talagan_OneSmallStep/images/indicator_insert.lua deleted file mode 100644 index 62f01a8bc..000000000 --- a/MIDI Editor/talagan_OneSmallStep/images/indicator_insert.lua +++ /dev/null @@ -1,13 +0,0 @@ --- @noindex --- @author Ben 'Talagan' Babut --- @license MIT --- @description This is part of One Small Step - -return "\z -\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z -\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x00\xA2\x49\x44\x41\x54\x38\x8D\xBD\x95\xDB\x0D\x80\x20\x0C\x45\x2F\xC4\x0D\x1C\xC1\x6D\x5C\xC9\z -\x0F\xD2\xA5\xDC\x8A\x0F\x27\xD0\x1F\xC1\xD2\x80\x3C\x6C\xBC\x09\xA1\x69\xE0\xD0\x07\x04\x73\x6E\xC7\x02\x60\x05\x30\xE3\x9B\x3C\x80\x7D\x12\x30\x37\x08\xA3\x9B\z -\xB1\x5A\x05\x18\xDF\x3B\x5B\x05\x58\x02\xB5\xB5\x55\xBD\x9A\x98\x4D\xB9\x13\x7B\xC5\x23\x74\x05\x7B\x18\xA8\xA2\xDF\x81\xC4\x66\x59\x63\xCA\xF9\x5B\x22\x24\x3C\z -\x35\x25\xE1\x0B\x23\x42\x5B\x80\x4E\xCC\x6F\x6B\x92\x6B\xD3\xA3\x24\x2A\x0D\x60\x02\x01\x2B\xCB\x68\x97\x65\x83\xA2\x4A\x2F\x85\x37\x22\xA7\xA6\x94\x73\x00\xE9\z -\xAB\xBE\xA6\x90\x72\x31\x85\x0E\x51\x00\x7A\x05\x68\xD8\xEB\x8D\xF6\x17\x70\x01\xE1\x64\x24\x05\x58\xE3\x2E\x77\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" -; diff --git a/MIDI Editor/talagan_OneSmallStep/images/indicator_delete.lua b/MIDI Editor/talagan_OneSmallStep/images/indicator_insert_back.lua similarity index 100% rename from MIDI Editor/talagan_OneSmallStep/images/indicator_delete.lua rename to MIDI Editor/talagan_OneSmallStep/images/indicator_insert_back.lua diff --git a/MIDI Editor/talagan_OneSmallStep/images/indicator_insert_forward.lua b/MIDI Editor/talagan_OneSmallStep/images/indicator_insert_forward.lua new file mode 100644 index 000000000..440b013c6 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/indicator_insert_forward.lua @@ -0,0 +1,15 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x00\xCE\x49\x44\x41\x54\x38\x8D\xAD\x95\x31\x12\x82\x30\x10\x45\x1F\x81\xD2\x8E\x23\x50\xEB\x41\z +\xB8\x92\x85\xE6\x52\x1C\xC0\x23\x68\xED\xD8\x58\x4A\xE1\x8C\x33\x56\x8C\x16\x26\x10\x42\x42\x42\xE4\x77\x99\xD9\xBC\xFD\xBB\xD9\x9D\x64\x9F\xFD\xB3\x02\x6A\xA0\z +\xE4\x3F\xB5\x40\x53\x58\xB0\x43\x22\x4C\x2A\x46\x2D\x56\x80\x99\x77\x4B\xB1\x02\x6C\x04\x15\xA1\x28\x4B\x32\x14\xB0\x14\x18\x84\xA6\x00\x67\xA1\xC5\x92\xEC\x4A\z +\x1D\x90\xAB\xD8\x49\xEF\x63\x1D\x76\xC0\x0B\xB8\x00\x27\x7E\x33\xE7\x34\x60\x3B\xD4\x3A\x06\x12\xDC\x19\xE6\x77\xE4\x34\xB5\x87\x57\xE0\x6C\x9C\x7B\xA7\xA9\xC0\z +\x0A\xD8\x19\xE7\xDE\x61\x6C\xC9\x1D\xF0\x06\x6E\xC0\x43\xC1\x9C\x1B\xE6\x03\xDA\xCA\x81\x0D\xB0\x65\x78\xE5\x09\xCC\x05\x0C\xAD\xA0\x9C\x83\x41\x7A\x0F\xBD\x89\z +\x53\x80\xB3\x55\x68\x60\xCC\x86\x84\x60\x52\x03\xBD\x53\xBF\x40\xFA\x6E\x9B\xAD\xFD\x05\x7C\x01\x09\xC0\x29\x7B\xE8\x6E\x0D\x79\x00\x00\x00\x00\x49\x45\x4E\x44\z +\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/indicator_navigate_back.lua b/MIDI Editor/talagan_OneSmallStep/images/indicator_navigate_back.lua new file mode 100644 index 000000000..a6353aee1 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/indicator_navigate_back.lua @@ -0,0 +1,17 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x01\x1F\x49\x44\x41\x54\x38\x8D\xAD\xD5\x3D\x4E\xC3\x40\x10\x86\xE1\xC7\xC4\x12\x42\xA2\x83\x32\z +\x0D\x4A\xC7\x11\x28\x50\x6A\x2E\x45\xD2\x73\x15\x5A\x5A\x7E\x4E\x40\x95\x02\x29\xA2\xA1\x84\x0E\x09\x45\x8A\x31\xC5\xEE\x86\xC8\xF1\x7A\x53\x64\x1A\x7B\xED\xF5\z +\x3B\xDF\xEC\xFC\xB8\x6A\xDB\xD6\x21\xED\xE8\xA0\x34\xD4\xED\x53\x9D\x7B\x37\xC1\x18\xE7\xF8\xC4\x07\x96\x43\xB0\x6A\xBA\x96\xA3\x4D\x70\x83\xB3\xB8\x5E\xE1\xAD\z +\x04\xA4\x3F\xE4\x2E\xEC\x16\xC7\xB8\x28\xC1\xB0\xA3\xB0\x0F\x96\xEC\x14\xB3\xCE\xFE\x06\x3F\x78\xC7\x2B\x96\xDB\xC0\x21\x58\xCE\x46\xD1\xD1\x65\x5C\x6F\x80\x39\z +\xD8\x3C\xDE\x97\xE0\x73\xF1\x48\xEA\x02\x6C\xFB\x9A\xB3\xB4\xFF\x84\x90\x94\xF1\x00\xAC\x11\x32\xDC\x14\xA0\x84\xF0\xD5\x42\x9D\xF5\xC1\xE0\x05\xCF\x19\xC0\xAC\z +\xEF\x61\x2D\x14\x6D\x02\xA5\xF3\x4A\xD0\x6B\x5C\xC5\x7D\xA3\x3D\x54\x3A\x12\x3A\xE0\xAB\xA3\x2E\xA9\x1D\x09\x35\xB8\x0F\xAC\x49\x0A\x97\x78\xF0\x9F\x98\xAE\xD2\z +\x7D\xCA\x87\x50\x8F\xAA\xDF\xC7\x8D\xF3\xA1\x3A\x2C\x65\xBA\xC1\xA2\x9A\xAE\xEF\xB7\x5B\x2F\x29\xED\x86\x5F\x02\x7D\x63\x21\x74\xCA\x4E\xEB\xE5\xC2\x17\x3F\xBC\z +\x2B\x79\xE8\x1B\x0E\x7D\x4A\x57\x42\xBF\x16\x2D\x37\xBE\x12\xB4\x3B\x0F\x8B\x56\x1D\xFA\x17\xF0\x07\x93\x7B\x4C\xAF\x67\xEB\x3C\xF0\x00\x00\x00\x00\x49\x45\x4E\z +\x44\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/indicator_navigate_forward.lua b/MIDI Editor/talagan_OneSmallStep/images/indicator_navigate_forward.lua new file mode 100644 index 000000000..db1f84120 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/indicator_navigate_forward.lua @@ -0,0 +1,16 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x01\x0D\x49\x44\x41\x54\x38\x8D\xAD\x95\xBD\x8A\xC2\x40\x14\x85\xBF\x68\x60\x11\xEC\xB4\x4C\x13\z +\x84\x2D\xB6\xF2\x0D\x64\x5B\xDB\x7D\x15\x5B\x89\xBE\x94\xB5\x8F\xE0\x0B\xC8\x36\x96\xB1\x16\x41\x99\x2D\xE6\x0E\x7B\x13\xE7\x4F\xC8\x69\x86\x09\x37\x5F\xCE\xC9\z +\xDC\xDC\x14\xC6\x18\x86\xD4\x68\x50\x1A\x50\x02\x98\x63\x99\xAA\x5B\x00\x15\x30\x07\x5A\xE0\x02\x9C\x83\xC0\x0C\x2D\x81\x4F\xE0\x43\xF6\x57\xE0\xE0\x83\xE6\x46\z +\xAE\x05\xD6\xC8\x7E\x06\xAC\xB1\xCE\x3B\x2A\x8C\x31\x98\x63\xB9\x10\x17\x35\x30\x01\xC6\x01\xB0\x03\xEE\x43\x4E\x9D\xC3\x25\xF0\x05\x4C\x23\x30\x1F\xF8\xC5\xA9\z +\x73\xB8\x11\x58\xE3\xB9\xB9\xAF\x7D\xCC\xA9\x03\x6E\xC5\x59\xA3\x8A\x72\x5D\x76\xA0\x2E\x72\x4E\xCC\x27\x70\x97\x55\x83\x74\xFC\x2A\xD6\x36\xBB\xC0\xF5\x15\xF0\z +\xAD\xA0\x0D\xFF\xC9\xE6\xEF\x00\x9F\xC0\x83\x6E\xEF\xF6\x63\xB7\xA5\x2A\x4E\xC5\x1E\xF7\x6A\x7C\xEF\xF0\xE2\x80\x37\xEC\x29\xEB\xC2\x90\xB2\x4E\xF9\x07\xDB\x87\z +\x29\x97\xFA\x61\xDE\xE6\x76\x0E\x4F\xB2\xA6\xBE\x94\x28\x4C\x03\xCF\x04\xA6\x87\xC8\x35\x7E\x14\x06\xF9\xC3\xE1\x17\xDB\x83\x51\x98\x76\x98\xD2\x09\x3B\x07\x93\z +\xF3\xB0\x18\xFA\x17\xF0\x07\x30\x6A\x5C\x0C\x36\x2B\x9A\x59\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/indicator_replace_back.lua b/MIDI Editor/talagan_OneSmallStep/images/indicator_replace_back.lua new file mode 100644 index 000000000..8a0a929f3 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/indicator_replace_back.lua @@ -0,0 +1,16 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x01\x0F\x49\x44\x41\x54\x38\x8D\xBD\xD4\xB1\x4A\xC3\x50\x14\x06\xE0\xAF\x6D\x96\x4A\x11\x44\x47\z +\x97\x22\x8E\x3E\x83\xBB\xAB\xAF\xE2\xD6\xA1\x66\xF7\x55\x5C\xDD\x5D\x9C\x05\x47\x29\x59\x1C\x95\x52\x09\x16\xA4\xA5\x0E\xB9\xB7\x4D\x4B\x9B\x4A\x0C\xFE\x53\xC2\z +\x25\x5F\x4E\x72\xCF\x3D\xAD\xC5\x60\x72\x83\x9E\x66\x92\x27\x01\x1B\x36\x04\xA6\x09\x72\xA4\x5B\x16\x8F\x70\x88\x03\x7C\xE1\x13\xE3\xDF\x54\x98\xA1\x8F\x2E\x3A\z +\x25\xEC\x3C\x60\x30\xC3\x47\x05\x38\xC7\x14\x59\x82\xFB\x8D\xC5\x33\x5C\x95\x1E\x1E\x86\x2F\xC8\x71\xB7\xA7\x42\xC9\x0E\xEC\xB8\x84\xC5\xF4\x70\xBB\xAB\x32\x3C\z +\x63\x54\x06\xAB\xB0\x5D\xE9\x84\x17\x5D\x84\xFB\x25\xB8\x0F\xDB\x87\xA7\x8A\x7D\xD0\xAE\x59\xD9\xB6\x74\x23\x78\xDA\x00\x46\xE8\x90\x36\x4E\x1A\xC0\x96\x69\xE3\z +\x3D\x5C\x6F\x6B\xEE\x5A\xE0\x9B\xA2\x69\xFF\x8A\xCE\x23\x38\xC2\x43\x03\xE8\x94\x55\x63\x47\x34\xEE\x76\x6A\xFD\x9F\xFE\xE6\x25\x59\xAC\x30\xA6\x4E\xA5\x73\xC5\z +\x91\x7C\x51\x9C\x14\xAD\xC5\x60\x72\x6D\x7D\x38\x6C\x0E\x86\x4B\x3C\xE2\x1B\x4F\x15\xF0\x14\x59\x3B\x60\x3D\xAB\x49\x33\xC6\xAB\x62\x64\x09\xD8\x4C\xF5\xE8\x8A\z +\x47\xB0\xFF\xAF\x03\xB6\x4E\xF2\x1F\xD1\xE8\x48\x36\x5C\xA6\xE7\xC6\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/indicator_replace_forward.lua b/MIDI Editor/talagan_OneSmallStep/images/indicator_replace_forward.lua new file mode 100644 index 000000000..97d90e246 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/indicator_replace_forward.lua @@ -0,0 +1,16 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x01\x0C\x49\x44\x41\x54\x38\x8D\xAD\xD4\xB1\x4A\x03\x41\x10\x00\xD0\xE7\xE5\x10\x22\x22\x48\x2C\z +\x2C\x6C\x8E\xD4\x42\x6A\x2B\x5B\x6D\xAD\xFD\x0B\x3B\x8B\x90\x0F\xB2\x4D\xEF\x1F\xD8\x4B\x48\x63\x69\x08\x4A\x48\x1A\x83\x16\xEE\x92\x25\x26\xB9\x55\x6F\x9B\xBD\z +\x3B\x86\xB7\xB3\xC7\xCC\xEC\x7D\xDE\xBF\xDD\xE1\x50\x33\x6B\x56\x06\xAC\xDF\x10\x38\x28\x31\xC3\xA0\x26\xF0\x18\x47\x38\xC0\x1C\xEF\x98\x6E\xCB\x70\x8C\x0A\x6D\z +\xB4\xB6\x80\xA7\xE8\xA0\x0C\xEF\x73\x3C\x27\xE8\x12\x0B\x8C\x4B\x3C\x64\x5C\x25\xFE\xE7\xBE\xD5\x6D\x26\x18\x62\x94\x06\xC6\x13\xBB\xE8\x65\x64\x2A\x41\x3B\xB8\z +\x5E\x47\x8B\xB0\xF7\x70\x1E\xB2\xD8\x85\xA5\xA8\x04\xED\xAE\x67\x58\xAD\x05\xE6\xAC\x8D\x99\xC6\x0C\xDB\xBF\x80\x76\x66\x1A\xC1\x9C\x6B\xE6\xA0\x67\xC5\xAE\xC8\z +\x3F\xA0\x27\x4D\x81\xB1\x94\x5E\x23\xB8\x6C\x00\x9B\xE0\x25\x82\x8B\x06\xB0\x21\x46\xB1\x6C\xC6\xBE\xEB\xB0\xAE\xA7\xD3\xB2\xDA\xD8\x31\x11\x7C\x0A\x7B\x4E\xA7\z +\x6C\xC5\x22\x78\x93\x01\x5D\x60\x3F\x3C\x3F\xE2\xD2\x6A\x40\xDC\x4A\x86\x43\x11\xB0\xBA\x96\x9B\xE2\x23\x60\xFC\x9C\x36\xAD\x60\x54\xFF\x19\xB0\x57\x1B\xBE\x65\z +\x0F\xD8\xDC\x35\xFB\x02\x4A\x8C\x42\xCF\x8F\x5C\x38\x72\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/indicator_back.lua b/MIDI Editor/talagan_OneSmallStep/images/indicator_write_back.lua similarity index 100% rename from MIDI Editor/talagan_OneSmallStep/images/indicator_back.lua rename to MIDI Editor/talagan_OneSmallStep/images/indicator_write_back.lua diff --git a/MIDI Editor/talagan_OneSmallStep/images/indicator_write_forward.lua b/MIDI Editor/talagan_OneSmallStep/images/indicator_write_forward.lua new file mode 100644 index 000000000..87f381423 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/indicator_write_forward.lua @@ -0,0 +1,15 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x00\xE8\x49\x44\x41\x54\x38\x8D\xAD\xD5\x31\x6A\xC3\x30\x18\x86\xE1\x27\x6D\xA1\x04\xBA\x35\x63\z +\x16\x13\xE8\x56\xC8\x39\x7A\x9E\x8E\x85\xE0\x4B\xE5\x1C\xB9\x80\xC9\x92\x31\x59\xBA\x94\x0E\xC1\x1D\x2C\x51\xB5\xB5\x2D\x15\xF4\x2D\x42\x20\xBF\xBC\x82\x4F\xBF\z +\x17\x7D\xDF\xAB\x99\x9B\xAA\x34\xDC\x81\xB7\xF7\xDC\xB9\x0D\xD6\x58\xE1\x8C\x13\xBA\x69\x60\x3E\x5B\x3C\xE1\x3E\xEC\x2F\xD8\x8F\x41\x4B\xAF\xDC\x04\xD8\x2E\xEC\z +\x1F\xF1\x62\x30\x1F\x35\xDC\x04\x8B\x06\x4B\xDC\xCE\xC0\x77\x68\x13\xE8\x0F\xD3\x68\xB8\xC5\x33\x1E\x32\xB0\x14\x3A\x6A\x1A\x0D\x9B\x5F\x07\x4B\x32\x6A\x1A\x0D\z +\x97\xFF\x00\xCD\x9A\x46\x60\xC9\x35\x4B\xA0\xEB\x5A\xC5\x8E\xD0\x55\x2D\x60\x1B\xD6\x73\x04\x5E\x2B\xC0\x2E\x38\x45\xE0\x47\x05\xD8\x1E\x5D\xAC\xCD\xD1\xD0\xC3\z +\x76\xEC\xAB\x24\x69\xAD\xFE\xC0\xF8\xEE\xE1\x21\xAC\x25\x2F\x65\x12\x96\x02\x3B\x13\xD3\x23\xE4\xD5\xF0\x8A\x66\x61\x94\x0F\x87\x23\x3E\x73\xB0\xD4\x30\x97\x83\z +\x61\x0E\x66\xE7\xE1\xA2\xF6\x2F\xE0\x0B\xF7\x38\x39\xAA\xB7\xDA\x59\x68\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/note_len_mode_igrid.lua b/MIDI Editor/talagan_OneSmallStep/images/note_len_mode_igrid.lua deleted file mode 100644 index c03b8a8a5..000000000 --- a/MIDI Editor/talagan_OneSmallStep/images/note_len_mode_igrid.lua +++ /dev/null @@ -1,13 +0,0 @@ --- @noindex --- @author Ben 'Talagan' Babut --- @license MIT --- @description This is part of One Small Step - -return "\z -\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x1E\x00\x00\x00\x1E\x08\x06\x00\x00\x00\x3B\x30\xAE\xA2\x00\x00\x00\x09\x70\x48\x59\z -\x73\x00\x00\x2E\x23\x00\x00\x2E\x23\x01\x78\xA5\x3F\x76\x00\x00\x00\x99\x49\x44\x41\x54\x48\x89\xED\x95\x4B\x0A\xC0\x20\x0C\x05\x63\xE9\x36\x8B\x9E\xA5\xF7\x3F\z -\x53\x17\xEF\x00\xE9\xA6\x2D\x45\x53\x09\x7E\x50\xAA\xB3\x53\x02\xA3\x21\xBC\x38\x11\xA1\x16\x2C\x4D\xAC\x53\xDC\x9D\x18\x80\x00\x28\x56\x67\x16\xD7\x60\x3C\xB1\z -\xF3\x03\x04\x40\x95\x44\x61\x66\xF7\x3E\xAF\xDA\x63\x94\x3B\xF9\xB8\x4F\xAD\xEB\xA8\xD5\x1A\x57\xFB\x1D\x33\x17\x13\x8F\x37\xD5\x53\x9C\x8B\x10\xD1\xDE\x42\x4C\z -\x44\xB4\x59\x8A\x82\x00\x89\x24\xD7\xB3\x79\xFC\x14\x4A\xA1\x74\x72\x99\x49\x6A\xB5\x75\xE7\xC6\x08\x7E\xAC\xA5\xD3\xAB\xC5\xD9\xC2\x9B\x1A\xC3\x75\x58\x8A\x4C\z -\x59\x5D\x83\xDF\x04\xC8\x14\xF7\x27\x3E\x01\x77\x0D\x34\xA3\x25\xE0\xE4\x98\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" -; diff --git a/MIDI Editor/talagan_OneSmallStep/images/note_len_mode_inote.lua b/MIDI Editor/talagan_OneSmallStep/images/note_len_mode_inote.lua new file mode 100644 index 000000000..59990ff38 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/note_len_mode_inote.lua @@ -0,0 +1,12 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x00\x73\x49\x44\x41\x54\x38\x8D\xED\x54\x41\x0E\xC0\x20\x08\x83\x65\x5F\xE8\xFF\xFF\x87\x8F\xE8\z +\x4E\x2E\x6E\x21\x3A\x18\xD9\x69\x4D\xBC\x88\x96\x36\x45\x95\xA4\x54\x62\x2B\x65\x13\x91\x3D\x73\xA9\xB5\x76\xDA\x02\xA0\x97\x22\xC9\xD4\x32\x33\x7A\xFB\xE5\x96\z +\x7F\xC2\x67\xE8\x29\x8F\x69\x77\xA8\x37\xD8\xC3\x41\x05\x10\x6A\xB6\x52\x18\x7E\x46\x33\x42\x9D\xD4\x52\x84\x29\xAC\x08\xC3\x2A\xBF\x55\x18\x4D\x58\xE4\xF6\xDB\z +\x78\x73\x15\x45\xB9\x65\x77\xB0\xDF\xA0\x5C\xE1\x01\xE9\xA2\x5A\x23\x44\x22\x38\x99\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/note_len_mode_pgrid.lua b/MIDI Editor/talagan_OneSmallStep/images/note_len_mode_pgrid.lua index d65e32150..238282b9f 100644 --- a/MIDI Editor/talagan_OneSmallStep/images/note_len_mode_pgrid.lua +++ b/MIDI Editor/talagan_OneSmallStep/images/note_len_mode_pgrid.lua @@ -4,11 +4,10 @@ -- @description This is part of One Small Step return "\z -\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x1E\x00\x00\x00\x1E\x08\x06\x00\x00\x00\x3B\x30\xAE\xA2\x00\x00\x00\x09\x70\x48\x59\z -\x73\x00\x00\x2E\x23\x00\x00\x2E\x23\x01\x78\xA5\x3F\x76\x00\x00\x00\xC2\x49\x44\x41\x54\x48\x89\xED\x95\x5D\x0E\xC2\x20\x10\x84\x67\x8C\xAF\xFB\xE0\x5D\x3C\x82\z -\x5C\xD2\xAB\x78\x86\x1E\xC1\x33\xF8\xB0\x07\x58\x1F\xAC\x06\x5B\xBA\xE9\x0F\x58\x62\x3B\x09\x09\x90\x09\x1F\x2C\x64\xA0\x99\x61\x0D\x1D\x56\xA1\xEE\xE0\xEA\xC0\z -\xAA\x6A\xAA\x9A\xCD\x37\x1A\x5C\x42\xDB\x03\xB3\x1B\x20\xAA\x5A\x24\x51\x44\x84\xF1\xF8\x98\xDA\x4C\x62\xCE\x06\xE6\xE7\xFA\x2A\x2A\x75\x4A\x6D\xF9\x29\x22\xD9\z -\xC0\xDB\x7B\xD5\x3B\x78\x89\x2C\x6A\x77\x00\x97\x5F\x81\x01\x20\x90\x24\x80\x2B\x80\x9B\x67\xEC\x05\x88\x93\x5C\x9F\x9F\xA7\x9B\x42\x5F\x26\xB3\x53\xDB\x7D\x4C\z -\x02\x63\x59\x72\xBD\x4F\xD9\x00\x08\x9E\x71\x56\xA9\x9D\x3F\x37\xF0\xA5\x33\xC9\xC6\x5B\xA3\x77\xE2\x54\x3A\x45\x25\x9E\xBE\xCB\x01\xE5\x7E\x5C\xEE\xBD\xC6\x1A\z -\x95\xD5\x25\xF4\x17\x01\xB2\x83\xEB\x04\x3F\x01\x37\x8E\x40\x36\x92\x78\x44\xFC\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x00\x94\x49\x44\x41\x54\x38\x8D\xAD\x54\x41\x0E\xC0\x20\x08\x2B\xCB\xBE\xC0\xFF\x1F\xC8\x23\xD8\z +\x65\x24\x8C\x08\x51\x46\x6F\x06\xA8\xAD\x34\x92\xAA\x62\x12\xD7\x28\x1B\x80\xFB\x74\x40\x44\x3E\x96\x98\x99\xFC\x39\x55\x28\x22\x2A\x22\xCB\x1A\x33\x93\x11\xC5\z +\x0B\x7E\x59\x8E\xEA\x7E\x13\x46\x75\x00\x40\x7E\xCB\xAB\x06\xEB\x63\xE6\x65\x4F\x54\x19\x97\xE2\x8B\x1A\xCE\x29\x89\xC7\x96\x65\x53\xB7\x83\x8F\x42\x3F\x68\x1B\z +\x3E\x21\x03\x1A\x4B\xA9\xEC\xB6\x08\x0D\x59\x46\x5B\x84\x45\x1A\xB6\x63\x53\xC2\x3F\x43\x2B\x36\x55\x6D\xFC\xB7\xA1\xEC\x3F\x7C\xED\xD3\x2A\x36\x55\x2D\x25\xEC\z +\x62\xDC\xF2\x38\xE1\x03\xD4\xE8\x43\x5F\x6B\x63\x0A\x55\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" ; diff --git a/MIDI Editor/talagan_OneSmallStep/images/note_modified.lua b/MIDI Editor/talagan_OneSmallStep/images/note_modified.lua index a48e27ba6..57c79120c 100644 --- a/MIDI Editor/talagan_OneSmallStep/images/note_modified.lua +++ b/MIDI Editor/talagan_OneSmallStep/images/note_modified.lua @@ -4,12 +4,12 @@ -- @description This is part of One Small Step return "\z -\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x1E\x00\x00\x00\x1E\x08\x06\x00\x00\x00\x3B\x30\xAE\xA2\x00\x00\x00\x09\x70\x48\x59\z -\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x00\xE8\x49\x44\x41\x54\x48\x89\xED\x96\x31\x0A\xC2\x30\x14\x86\xBF\x88\xE2\xF4\x86\x0E\x82\x73\z -\x5D\xDC\xF5\x08\x3D\x81\xA0\x27\x71\xF0\x0A\xBD\x82\x38\xBA\xA8\x57\x70\xF0\x00\x16\xBC\x80\xBD\x82\x43\xA6\x1A\xA1\x0E\xAD\x50\x34\x05\x2B\xD5\x0E\xE6\x87\x07\z -\x79\xC9\x4B\x3E\xDE\x7B\x24\x44\xA5\x69\x4A\x13\x6A\x35\x42\x75\x60\x07\x2E\x4A\x29\xF5\x62\xD7\xDB\xED\xF4\x75\x70\x89\xFA\x4D\x81\x3F\x96\x03\x3B\xB0\x03\x3B\z -\xF0\xC7\x6A\x57\xDD\x90\x18\x33\x01\x7A\x3F\x05\x27\xC6\x1C\x80\xA1\x6D\x4D\x6B\xED\x03\xE7\xDC\x9D\x01\x5B\x60\x21\x22\xA1\x2D\xFE\xED\x52\x27\xC6\xAC\x2C\x50\z -\xF3\x18\x88\x48\x0C\x2C\x80\x18\x08\x80\x3D\xE0\x95\x9D\x57\xA5\xC7\x63\xCB\xDC\xE6\xC9\x1F\x01\x3E\x10\xE6\xE3\xA8\x0E\x70\x11\x62\x80\x75\xB7\xD3\x99\x3F\xC5\z -\x04\xC0\x92\x2C\x53\x8F\x2C\x6B\xAB\x54\x5D\xDF\x5B\xAD\xF5\x08\x38\x02\x03\x60\x9A\x5B\x28\x22\x3B\x5B\x7C\x9D\xD7\x29\x00\xA2\xBC\xD7\x90\x95\xFC\x52\x16\x5C\z -\x5B\xC6\x55\xF5\x7F\x2F\xD7\xFF\x81\xEF\x0F\x62\x32\xD0\x63\x1C\xF7\xDF\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x00\xCE\x49\x44\x41\x54\x38\x8D\xD5\x94\xC1\x11\x82\x30\x10\x45\x1F\x8E\x0D\xD0\x02\x2D\xD0\x82\z +\x2D\xD0\x82\xB6\x60\x0B\x96\x80\x25\x68\x0B\x29\x41\x5A\xB0\x04\x2D\x21\x1E\xB2\x3B\x13\x03\x24\x9B\x19\x0E\xBA\x33\x4C\x16\x0E\x2F\x7F\xF9\x3F\x69\xBC\xF7\x6C\z +\x59\xBB\x4D\x69\x7F\x09\x3C\x00\x1E\x78\x01\xA3\xAC\xB9\x9A\x19\x90\x02\x1D\x70\x07\x5A\xE0\x69\x80\x35\x25\xA0\xAA\x74\x02\x74\x35\xB0\x25\x60\x2F\xEA\x4E\xD2\z +\xBF\x81\xCE\x0A\x03\xD8\x2F\xA8\x9B\x44\x5D\x27\x4F\x3C\x7A\x16\x06\xD0\x54\x04\xBB\x08\x03\x7B\x6C\x4C\x30\x2B\xD0\x0C\xB3\x00\x63\xD8\x51\xDE\x47\xE0\x01\xDC\z +\xA4\xF7\x44\xC6\xE5\x80\xA9\xB2\x2B\xC1\xF5\x9E\x60\x9C\x1A\x88\x7C\xCF\x02\x97\xC6\xD4\x48\x9D\xA5\xD7\x0D\xA6\x12\x70\xED\x9F\xA9\xA2\x49\x80\x17\x59\xBF\xC2\z +\x9F\xE6\x90\x15\x18\xC0\x40\x38\x96\x43\xA4\x4A\xB3\xDA\xAA\xCA\x9A\x1C\x9A\xEA\xF7\xEF\xC3\x0F\x6D\x48\x38\x92\x50\x58\xB8\x41\x00\x00\x00\x00\x49\x45\x4E\x44\z +\xAE\x42\x60\x82" ; diff --git a/MIDI Editor/talagan_OneSmallStep/images/snap.lua b/MIDI Editor/talagan_OneSmallStep/images/snap.lua new file mode 100644 index 000000000..b636c5769 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/snap.lua @@ -0,0 +1,17 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x01\x30\x49\x44\x41\x54\x38\x8D\xCD\xD4\xCD\x2A\x84\x51\x1C\xC7\xF1\xCF\x78\x5D\xDA\x78\x56\x2E\z +\x80\x94\x9A\x6B\x50\x94\x99\xEC\xEC\x64\x29\x0B\x65\xED\x16\x5C\x01\x0B\x59\xB8\x02\x65\x61\x61\xC3\x4A\x21\x2B\x0B\x1B\xA5\x6C\xE8\x51\x28\x0D\x9A\x34\x16\xF3\z +\x8C\x8E\xE3\x8C\xB7\x46\xF9\xD7\xA9\xE7\x77\xFE\xBF\xFF\xF7\xBC\x3D\xE7\x94\x1A\x8D\x86\x4E\x46\x57\x47\x69\x7F\x01\xEC\x09\x45\x9E\xE7\x55\x2C\xA2\x17\x77\xD8\z +\xC0\x4E\x54\x33\x83\xF9\x62\x32\x35\xAC\x65\x59\xF6\xE6\xE9\x89\xCC\x63\x98\x0A\xF4\x49\x02\x58\xC6\x64\xA0\x0F\x42\xCF\x57\x4B\x7E\x4E\xF4\x3D\x44\xBA\x16\x8A\z +\x78\x86\x5B\x38\x2F\xBE\xEB\x38\x4E\x00\x5B\x9E\x7A\x01\x3F\xFB\x0C\x78\x8F\x0B\x0C\x24\xE7\xDB\x8C\x47\xDC\xB6\x4B\xC6\x4B\x9E\xC3\x21\x76\x8B\x36\x9D\xA8\x99\z +\x0D\xF2\x1F\x3C\xBF\xF9\x6D\x52\xFB\xDA\x16\xF8\x9D\x01\x7A\x7F\x02\xAC\x47\xBA\x3F\x51\x33\x14\xE9\x77\x77\x37\x06\x5E\x47\xBA\x82\x52\xA0\xFB\x30\x1E\x79\x4E\z +\x43\x11\x9F\xF2\x3E\x5E\xD0\x5D\xE8\x89\xA2\x60\x4F\x73\xEF\x2A\x18\x0E\xFC\x35\x1C\x7D\x06\xBC\xC4\x3A\x16\x82\xBE\xD1\xA2\xA5\x62\x55\x74\x48\xA9\x43\x58\xC2\z +\x66\x1B\x40\x2B\x9E\xB0\x82\xE5\x38\x51\x0A\xDF\xC3\x3C\xCF\xC3\x5C\x19\x55\x8C\x60\x50\x73\x79\x57\x9A\xB7\x67\x1B\x37\x2D\x63\x96\x65\x69\x60\x27\xE2\xFF\x3F\z +\xB0\xAF\x39\x7A\x45\x30\x77\xA7\x54\x67\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/snap_btn_ibounds.lua b/MIDI Editor/talagan_OneSmallStep/images/snap_btn_ibounds.lua new file mode 100644 index 000000000..a24ce646e --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/snap_btn_ibounds.lua @@ -0,0 +1,15 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x00\xED\x49\x44\x41\x54\x38\x8D\xC5\x94\xBD\x6A\x02\x51\x10\x46\xCF\x6A\xB2\x16\x5A\x89\x8B\x20\z +\xD6\x3E\x83\x81\xE0\x03\xC4\x2E\x4D\xBA\xB4\x79\x02\x5F\xC1\x3E\x4D\x20\x4D\xC0\x77\xF0\x01\x2C\xED\xD3\x08\x06\x52\x85\x14\x5B\xD9\x58\x04\xC2\x49\x91\x0D\x04\z +\x71\xFF\x74\x61\x3F\x98\x6E\xE6\xDC\xF9\xE6\xCE\xBD\x81\x4A\x95\x6A\x54\x4A\x03\x2E\xCA\x16\xC4\x71\x7C\xD4\x52\x14\x45\xC1\x49\xC0\xFF\xC5\xC7\x0E\xA9\xDF\x32\z +\xA4\xDB\x06\x08\xEA\xBE\xE5\xDC\xFC\xA2\xC0\x0E\xF0\x00\xF4\xAA\x00\xF6\x80\x27\xA0\x0B\xC4\xB9\xD9\x6A\x56\xB4\xD5\x85\xFA\xA9\x86\x39\xB9\xA8\x99\xC0\x4B\x75\z +\xEE\xAF\xC6\x45\x60\x59\xC0\xB6\xFA\xA2\x7E\xA9\x8F\x45\x61\x69\xC0\x2B\xF5\x35\xE9\xEC\x5B\x5D\xAA\xB7\x6A\xF3\x54\x60\x5F\xBD\x57\x9F\xD5\x5D\x02\xDE\xA8\xD3\z +\x73\x67\x78\x97\x58\xDE\xA8\xD7\x6A\x70\x0E\x30\x54\x3F\xD4\x95\x3A\x2C\x33\xC3\xB4\xB7\x3C\x03\xB6\xC0\x0D\xB0\x2F\xB0\xAB\x99\x7B\x38\x52\xD7\xEA\xA0\x4C\x67\z +\x7F\x71\xF8\x39\xB4\x80\x09\xF0\x06\xBC\x97\xEA\x2C\xD1\x0F\x9F\x45\x0C\xC9\x88\xBF\x37\xE3\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/snap_btn_igrid.lua b/MIDI Editor/talagan_OneSmallStep/images/snap_btn_igrid.lua new file mode 100644 index 000000000..7db816ac0 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/snap_btn_igrid.lua @@ -0,0 +1,16 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x01\x00\x49\x44\x41\x54\x38\x8D\xB5\x94\x31\x4A\x04\x31\x14\x86\xBF\x59\x74\x85\x5D\xCB\x1D\x04\z +\xB1\xB6\xDA\x03\x28\x88\x17\xF0\x00\x76\xB6\x9E\x41\xEC\xED\x2D\xB5\x58\xD0\x1B\x58\xD9\x5A\x7A\x84\x2D\x04\x2B\x11\x66\x2A\x5B\x41\x3F\x0B\x07\xC9\x68\x36\x9B\z +\x59\xC6\x07\x29\xC2\x4B\xBE\xBC\xFF\x7F\x49\x0A\x95\x3E\x63\xD0\x2B\x0D\x58\x5B\x65\x53\x5D\xD7\x3F\xB2\xCA\xB2\x2C\x5A\x49\x35\x3A\xAA\xAA\x72\x51\x2E\x95\xEF\z +\x5D\xF2\xFF\x7A\x18\x7A\x13\xCE\xFF\xF8\x94\x8A\x8E\x1E\x0D\xFA\xF2\x70\x13\x38\x05\x26\x61\xE5\xBF\x15\x25\x2B\x0C\xC6\x44\xBD\x55\xCF\xD4\x62\xD9\xFA\x65\xB0\z +\xB1\x7A\xA3\xBE\xAA\xC3\x8C\xC3\x93\xC0\x75\xF5\xC2\xEF\xD8\xCB\x81\xA5\x80\x63\x75\xA6\xBE\xAB\x97\x5D\x2E\x7D\x11\xF9\x1C\xF6\x81\x6B\x60\x0A\x7C\x02\xF7\xC0\z +\x0C\xB8\x03\x3E\x62\x8D\x68\x5D\xAB\xC8\x29\x5B\xEA\x89\x7A\xA5\xBE\x35\x92\xE7\xEA\x51\x4E\x85\x29\x3F\x8E\x1B\xC9\x73\xF5\x20\xEC\xF0\x2A\xC0\xA1\xFA\xA2\x3E\z +\xA8\x3B\x5D\x3C\x5C\x04\x3C\x6F\x60\xA3\xDC\xEE\xA6\x80\xBB\xEA\xA3\xBA\xDD\x15\x16\xEB\xF2\x06\x70\x08\x3C\x01\xCF\x99\xCF\xB2\x15\x5F\x6C\x76\xD0\xB8\x2C\xFE\z +\x49\x4A\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/snap_btn_note.lua b/MIDI Editor/talagan_OneSmallStep/images/snap_btn_note.lua new file mode 100644 index 000000000..81477c750 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/snap_btn_note.lua @@ -0,0 +1,16 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x00\xFD\x49\x44\x41\x54\x38\x8D\xAD\x94\xB1\x4A\x03\x41\x14\x45\xCF\xA8\xD1\x22\x96\x59\x84\x60\z +\x9D\x6F\x88\x20\x76\x36\xDA\xD9\xD8\x59\x09\x7E\x81\xBF\x90\x4E\xC1\x32\x4D\xBE\xC2\x0F\xB0\x4C\x9F\xC2\x80\x82\x95\xD5\x56\x36\x16\x82\x1C\x0B\x37\x9A\x0D\x93\z +\x64\x27\xBB\x17\x5E\xF3\xE6\xCD\xE1\xBE\xDD\xCB\x04\x95\x26\xB5\xB3\xE9\xC5\x3C\xCF\x67\x4E\x42\x96\x65\x7F\xFD\xAD\xBA\x8E\x80\xD2\x8A\x75\x81\x61\xB1\xD1\x84\z +\xC3\xC6\x81\x25\x97\x29\xC0\x4A\xB3\x55\x86\xF6\x81\x1B\xA0\x13\x3B\x9C\xFF\xC3\xB0\x3E\x36\x1D\xE0\x1E\x78\x06\x72\x28\xC5\x25\xAA\x55\xC0\x36\x70\x07\x9C\x02\z +\xD7\x2C\xC4\x63\xA9\xD4\x58\xB5\xD4\x81\xBF\xEA\x2F\x99\x89\x56\xAC\xD9\x56\x47\xEA\x97\xFA\x90\x02\x8B\x01\x8F\xD4\x49\xE1\xEC\x5B\x7D\x54\x2F\xD4\xED\x4D\x81\z +\x07\xEA\x95\x3A\x54\x3F\x0A\xF0\x54\x3D\xAF\xB3\x32\xEA\x65\xB1\xF2\x54\x3D\x56\x43\x1D\xE0\xAE\xFA\xAE\x3E\xA9\x87\xA9\xDF\x30\x16\x9B\x5B\xE0\x05\x38\x03\x3E\z +\x2B\x45\x65\x45\x6C\x7A\xEA\x58\xED\xA6\x3A\x9B\x55\xF0\xFF\xC5\xDE\x03\x4E\x80\x57\xE0\x2D\xD9\x59\xA1\x79\x60\x23\xFA\x01\xDB\x19\xCF\x9C\xD9\xEC\xAB\x38\x00\z +\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/snap_btn_pgrid.lua b/MIDI Editor/talagan_OneSmallStep/images/snap_btn_pgrid.lua new file mode 100644 index 000000000..af81176e3 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/snap_btn_pgrid.lua @@ -0,0 +1,16 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +return "\z +\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8D\x89\x1D\x0D\x00\x00\x00\x09\x70\x48\x59\z +\x73\x00\x00\x0B\x13\x00\x00\x0B\x13\x01\x00\x9A\x9C\x18\x00\x00\x01\x0E\x49\x44\x41\x54\x38\x8D\xAD\x93\x31\x4A\xC4\x40\x14\x86\xBF\x2C\xBA\x82\x6B\x25\x1B\x04\z +\xB1\xB6\xF2\x00\x0A\xE2\x05\x3C\x80\x9D\xAD\x87\xB0\xB7\xB7\x11\xB4\x58\xF0\x08\x56\xB6\x96\x1E\x61\x0B\xC1\x4A\x84\xA4\xB2\x15\xF4\xB3\x30\x4A\x12\x66\x32\x09\z +\xD9\x07\x53\xCC\xF0\xE6\x9B\xFF\x7F\xEF\x4D\xA6\xB2\xCA\x98\xAC\x94\x06\xAC\x0D\xBD\x50\x96\x65\xC3\x52\x9E\xE7\x59\x7D\x1F\x55\xD8\xBE\xD8\x86\xFC\x81\xDA\x79\z +\xA3\x2C\xB7\xD5\x8D\x06\x86\x5C\x64\xF5\x2E\xC7\x6C\xD6\x95\xA4\x6A\x88\x1A\x5C\x45\x51\x18\x38\x9F\x44\xCE\xFF\x57\x5F\xCB\x5B\xC0\x05\x30\x4F\x25\x46\x81\x35\z +\x2B\x73\xE0\x06\xD8\x06\xCA\xE4\xD3\x5D\xF2\xD5\x99\x7A\xAF\xBE\xAB\xD3\x44\x2E\x6A\x27\x70\x5D\xBD\xF2\x37\x0E\xFB\xC0\xBA\x80\x33\x75\xA1\x7E\xAA\xD7\x3D\x1B\z +\x86\xDA\x1C\x9B\x2A\x8E\x80\x3B\xE0\x00\xF8\x06\x1E\x81\x05\xF0\x00\x7C\x85\x46\xAB\x31\x3A\x81\x57\x76\xD4\x73\xF5\x56\xFD\xA8\x2C\x2F\xD5\xD3\x3E\x0A\xBB\xEA\z +\x71\x56\x59\x5E\xAA\xC7\x6A\x36\x06\x38\x55\xDF\xD4\x27\x75\x6F\x48\x0D\x63\xC0\xCB\x0A\xB6\xD9\xB7\xBB\x5D\xC0\x7D\xF5\x59\xDD\x1D\x0A\x0B\x75\x79\x03\x38\x01\z +\x5E\x80\xD7\xE4\xAF\x08\xC4\x0F\x03\xCA\x60\x25\x43\x42\x87\xB3\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +;