From d0207c1d594661f717ca2732d5994f2c39655db3 Mon Sep 17 00:00:00 2001 From: BenTalagan Date: Fri, 9 Feb 2024 19:28:30 +0100 Subject: [PATCH] Update OneSmallStep v0.1 > v0.8 --- ...agan_OneSmallStep Change note len mode.lua | 19 ++ ..._OneSmallStep Change note len modifier.lua | 4 +- MIDI Editor/talagan_OneSmallStep.lua | 300 ++++++++++++++++-- .../images/note_len_mode_igrid.lua | 13 + .../images/note_len_mode_oss.lua | 24 ++ .../images/note_len_mode_pgrid.lua | 14 + .../images/note_tuplet.lua | 15 + .../talagan_OneSmallStep Engine lib.lua | 119 +++++-- 8 files changed, 454 insertions(+), 54 deletions(-) create mode 100644 MIDI Editor/talagan_OneSmallStep Change note len mode.lua create mode 100644 MIDI Editor/talagan_OneSmallStep/images/note_len_mode_igrid.lua create mode 100644 MIDI Editor/talagan_OneSmallStep/images/note_len_mode_oss.lua create mode 100644 MIDI Editor/talagan_OneSmallStep/images/note_len_mode_pgrid.lua create mode 100644 MIDI Editor/talagan_OneSmallStep/images/note_tuplet.lua diff --git a/MIDI Editor/talagan_OneSmallStep Change note len mode.lua b/MIDI Editor/talagan_OneSmallStep Change note len mode.lua new file mode 100644 index 000000000..8f3a68327 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep Change note len mode.lua @@ -0,0 +1,19 @@ +-- @noindex +-- @author Ben 'Talagan' Babut +-- @license MIT +-- @description This is part of One Small Step + +package.path = debug.getinfo(1,"S").source:match[[^@?(.*[\/])[^\/]-$]] .."?.lua;".. package.path; + +local mode = select(2, reaper.get_action_context()):match("%- ([^%s]*)%.lua$"); + +local engine_lib = require "talagan_OneSmallStep/talagan_OneSmallStep Engine lib"; + + +if mode == 'OSS' then + engine_lib.setNoteLenMode(engine_lib.NoteLenMode.OSS); +elseif mode == 'ItemConf' then + engine_lib.setNoteLenMode(engine_lib.NoteLenMode.ItemConf); +elseif mode == 'ProjectGrid' then + engine_lib.setNoteLenMode(engine_lib.NoteLenMode.ProjectGrid); +end \ No newline at end of file diff --git a/MIDI Editor/talagan_OneSmallStep Change note len modifier.lua b/MIDI Editor/talagan_OneSmallStep Change note len modifier.lua index 837b92362..34a5633f2 100644 --- a/MIDI Editor/talagan_OneSmallStep Change note len modifier.lua +++ b/MIDI Editor/talagan_OneSmallStep Change note len modifier.lua @@ -16,4 +16,6 @@ elseif modifier == 'Dotted' then engine_lib.setNoteLenModifier(engine_lib.NoteLenModifier.Dotted); elseif modifier == 'Straight' then engine_lib.setNoteLenModifier(engine_lib.NoteLenModifier.Straight); -end \ No newline at end of file +elseif modifier == 'Tuplet' then + engine_lib.setNoteLenModifier(engine_lib.NoteLenModifier.Tuplet); +end diff --git a/MIDI Editor/talagan_OneSmallStep.lua b/MIDI Editor/talagan_OneSmallStep.lua index 468c59646..b3888c1dc 100644 --- a/MIDI Editor/talagan_OneSmallStep.lua +++ b/MIDI Editor/talagan_OneSmallStep.lua @@ -1,14 +1,18 @@ --[[ @description One Small Step : Alternative Step Input -@version 0.1 +@version 0.8 @author Ben 'Talagan' Babut @license MIT @metapackage @provides [main=main,midi_editor] . + [main=main,midi_editor] talagan_OneSmallStep Change note len mode.lua > talagan_OneSmallStep Change note len modifier - OSS.lua + [main=main,midi_editor] talagan_OneSmallStep Change note len mode.lua > talagan_OneSmallStep Change note len modifier - ItemConf.lua + [main=main,midi_editor] talagan_OneSmallStep Change note len mode.lua > talagan_OneSmallStep Change note len modifier - ProjectGrid.lua [main=main,midi_editor] talagan_OneSmallStep Change note len modifier.lua > talagan_OneSmallStep Change note len modifier - Triplet.lua [main=main,midi_editor] talagan_OneSmallStep Change note len modifier.lua > talagan_OneSmallStep Change note len modifier - Straight.lua [main=main,midi_editor] talagan_OneSmallStep Change note len modifier.lua > talagan_OneSmallStep Change note len modifier - Dotted.lua + [main=main,midi_editor] talagan_OneSmallStep Change note len modifier.lua > talagan_OneSmallStep Change note len modifier - Tuplet.lua [main=main,midi_editor] talagan_OneSmallStep Increase note len.lua [main=main,midi_editor] talagan_OneSmallStep Decrease note len.lua [main=main,midi_editor] talagan_OneSmallStep Change note len.lua > talagan_OneSmallStep Change note len - 1_64.lua @@ -29,7 +33,12 @@ @screenshot https://stash.reaper.fm/48161/One%20Small%20Step%200.1.png @changelog - Initial version. + - MIDI Items are now extended if the input notes overflow + - Allow the use of the commit action in keyboard mode to insert rests + - Allow the use of the commit action in pedal mode to act as the sustain pedal + - Added Project Grid and MIDI Item conf modes to change the source for the note length + - Added support for n-tuplets + - Bug Fix : When launched from a toolbar button, update the button to OFF state when crashing or being terminated by REAPER @about # Purpose @@ -47,7 +56,7 @@ # Reaper forum thread - The forum thread does not exist yet (at release time). Please search "One Small Step" on reaper forums for now (until a new version is released and the doc is updated). + The official discussion thread is located here : https://forum.cockos.com/showthread.php?t=288076 # How to use @@ -64,10 +73,12 @@ ### Keyboard Notes are added to the MIDI item at the current position, when the keys are released. + Rests can also be inserted in this mode, by calling the 'OneSmallStep Commit' action. ### Sustain Pedal Hold keys on your MIDI controller, then press the sustain pedal to validate them. This is convenient when playing with chords for example. + In this mode, the 'OneSmallStep Commit' action will behave like the sustain pedal. ### Action @@ -75,11 +86,23 @@ ## Note length - You can adjust the length of the input notes here. + 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). ## Other 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 the "Change note len", "Decrease/Increase note len", "Toggle note len modifier" actions, whose names should be safe 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). + To speed up your flow, multiple actions are provided to quickly change OSS parameters, so that you can assign shortcuts to them. Those are the "Change note len", "Decrease/Increase note len", "Change note len modifier", "Change note len mode" 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). # Toolbar icons @@ -176,11 +199,15 @@ function ButtonGroupTextButton(text, is_on, callback) reaper.ImGui_SameLine(ctx); end -function ButtonGroupImageButton(image_name, is_on, callback) +function ButtonGroupImageButton(image_name, is_on, callback, corner) reaper.ImGui_SetCursorPosY(ctx,reaper.ImGui_GetCursorPosY(ctx) - 3); reaper.ImGui_PushStyleColor(ctx, reaper.ImGui_Col_Button(), is_on and 0x5080FFFF or 0x203040FF); - if reaper.ImGui_ImageButton(ctx, image_name, getImage(image_name), 20, 20, 0.1, 0.1, 0.9, 0.9, 0, 0xFFFFFFFF) then + if corner == nil then + corner = 0.1 + end + + if reaper.ImGui_ImageButton(ctx, image_name, getImage(image_name), 20, 20, corner, corner, 1 - corner, 1 - corner, 0, 0xFFFFFFFF) then callback(); end @@ -188,6 +215,138 @@ function ButtonGroupImageButton(image_name, is_on, callback) reaper.ImGui_SameLine(ctx); end +function ImGui_NoteLenImg(context, image_name, triplet, divider) + reaper.ImGui_SetCursorPosY(ctx,reaper.ImGui_GetCursorPosY(ctx) - 3); + reaper.ImGui_Image(ctx, getImage(image_name), 20, 20, 0.1, 0.1, 0.9, 0.9); + + if triplet then + reaper.ImGui_SameLine(ctx); + reaper.ImGui_SetCursorPosX(ctx, reaper.ImGui_GetCursorPosX(ctx) - 20); + reaper.ImGui_SetCursorPosY(ctx, reaper.ImGui_GetCursorPosY(ctx) - 10); + ImGui_NoteLenImg(ctx, "note_triplet"); + end + + if divider then + reaper.ImGui_SameLine(ctx); + reaper.ImGui_SetCursorPosY(ctx,reaper.ImGui_GetCursorPosY(ctx) + 3); + reaper.ImGui_TextColored(ctx, 0xC0C0C0FF, divider); + end +end + +function ImGui_QNToLabel(ctx, qn) + + -- We have to do a reverse translation from the info given by GetProjectGrid... + -- And it's TEDIOUS + + + -- I don't have enough icons, cheat + if qn == 4 then + ImGui_NoteLenImg(ctx, "note_1", false, "x 4"); + elseif qn == 4 * (3/2.0) then + ImGui_NoteLenImg(ctx, "note_1", false, ". x 4"); + elseif qn == 4 * (2/3.0) then + ImGui_NoteLenImg(ctx, "note_1", true, "x 4"); + + -- I don't have enough icons, cheat + elseif qn == 2 then + ImGui_NoteLenImg(ctx, "note_1", false, "x 2"); + elseif qn == 2 * (3/2.0) then + ImGui_NoteLenImg(ctx, "note_1", false, ". x 2"); + elseif qn == 2 * (2/3.0) then + ImGui_NoteLenImg(ctx, "note_1", true, "x 2"); + + elseif qn == 1 then + ImGui_NoteLenImg(ctx, "note_1"); + elseif qn == 1 * (3/2.0) then + ImGui_NoteLenImg(ctx, "note_1", false, "."); + elseif qn == 1 * (2/3.0) then + ImGui_NoteLenImg(ctx, "note_1", true); + + elseif qn == 0.5 then + ImGui_NoteLenImg(ctx, "note_1_2"); + elseif qn == 0.5 * (3/2.0) then + ImGui_NoteLenImg(ctx, "note_1_2", false, "."); + elseif qn == 0.5 * (2/3.0) then + ImGui_NoteLenImg(ctx, "note_1_2", true); + + elseif qn == 0.25 then + ImGui_NoteLenImg(ctx, "note_1_4"); + elseif qn == 0.25 * (3/2.0) then + ImGui_NoteLenImg(ctx, "note_1_4", false, "."); + elseif qn == 0.25 * (2/3.0) then + ImGui_NoteLenImg(ctx, "note_1_4", true); + + elseif qn == 0.125 then + ImGui_NoteLenImg(ctx, "note_1_8"); + elseif qn == 0.125 * (3/2.0) then + ImGui_NoteLenImg(ctx, "note_1_8", false, "."); + elseif qn == 0.125 * (2/3.0) then + ImGui_NoteLenImg(ctx, "note_1_8", true); + + elseif qn == 0.0625 then + ImGui_NoteLenImg(ctx, "note_1_16"); + elseif qn == 0.0625 * (3/2.0) then + ImGui_NoteLenImg(ctx, "note_1_16", false, "."); + elseif qn == 0.0625 * (2/3.0) then + ImGui_NoteLenImg(ctx, "note_1_16", true); + + elseif qn == 0.03125 then + ImGui_NoteLenImg(ctx, "note_1_32"); + elseif qn == 0.03125 * (3/2.0) then + ImGui_NoteLenImg(ctx, "note_1_32", false, "."); + elseif qn == 0.03125 * (2/3.0) then + ImGui_NoteLenImg(ctx, "note_1_32", true); + + elseif qn == 0.015625 then + ImGui_NoteLenImg(ctx, "note_1_64"); + elseif qn == 0.015625 * (3/2.0) then + ImGui_NoteLenImg(ctx, "note_1_64", false, "."); + elseif qn == 0.015625 * (2/3.0) then + ImGui_NoteLenImg(ctx, "note_1_64", true); + + -- I don't have enough icons, cheat + elseif qn == 0.0078125 then + ImGui_NoteLenImg(ctx, "note_1", false, "/ 128"); + elseif qn == 0.0078125 * (3/2.0) then + ImGui_NoteLenImg(ctx, "note_1", false, ". / 128"); + elseif qn == 0.0078125 * (2/3.0) then + ImGui_NoteLenImg(ctx, "note_1", true, "/ 128"); + end +end + + +-- Indicator for the current project grid note len +function ImGui_ProjectGridLabel(ctx) + local _, qn, swing, _ = reaper.GetSetProjectGrid(0, false); + + 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); + end + reaper.ImGui_PopStyleVar(ctx,1); +end + +-- Indicator for the current MIDI item note len +function ImGui_ItemGridLabel(ctx,take) + if not take then + return + end + + local grid_len, swing, note_len = reaper.MIDI_GetGrid(take); + + if note_len == 0 then + note_len = grid_len; + end + + local qn = note_len/4; + + reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_ItemSpacing(),0, 0); + ImGui_QNToLabel(ctx, qn); + reaper.ImGui_PopStyleVar(ctx,1); +end + function ImGui_VerticalSpacer(context, height) reaper.ImGui_PushStyleVar(context, reaper.ImGui_StyleVar_ItemSpacing(),0,0) reaper.ImGui_Dummy(context, 10, height); @@ -195,8 +354,8 @@ function ImGui_VerticalSpacer(context, height) end function ui_loop() - reaper.ImGui_PushStyleVar(ctx,reaper.ImGui_StyleVar_WindowPadding(),10,10); + reaper.ImGui_PushStyleVar(ctx,reaper.ImGui_StyleVar_WindowPadding(),10,10); -- local flags = reaper.ImGui_WindowFlags_NoDocking() | reaper.ImGui_WindowFlags_NoCollapse() | @@ -205,7 +364,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.1', true, flags); + local visible, open = reaper.ImGui_Begin(ctx, 'One Small Step v0.8', true, flags); reaper.ImGui_PopStyleColor(ctx,1); if visible then @@ -295,46 +454,116 @@ function ui_loop() -- Separator reaper.ImGui_NewLine(ctx); - ImGui_VerticalSpacer(ctx,5); + ImGui_VerticalSpacer(ctx,7); -- Note length line reaper.ImGui_Text(ctx, "Note Length"); reaper.ImGui_SameLine(ctx); + reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_FramePadding(), 0, 0); reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_ItemSpacing(), 2, 4); reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_ItemInnerSpacing(), 0, 0); - local nl = engine_lib.getNoteLen(); - for s,k in ipairs({ "1", "1_2", "1_4", "1_8", "1_16", "1_32", "1_64" }) do - ButtonGroupImageButton('note_'.. k, nl==k, - function() - engine_lib.setNoteLen(k) - end - ); + local nlm = engine_lib.getNoteLenMode(); + + ButtonGroupImageButton('note_len_mode_oss', nlm == engine_lib.NoteLenMode.OSS, function() engine_lib.setNoteLenMode(engine_lib.NoteLenMode.OSS) end, 0); + if reaper.ImGui_IsItemHovered(ctx, reaper.ImGui_HoveredFlags_DelayNormal()) then + reaper.ImGui_SetTooltip(ctx, 'Use One Small Step conf (aside)') + end + + ButtonGroupImageButton('note_len_mode_pgrid', nlm == engine_lib.NoteLenMode.ProjectGrid, function() engine_lib.setNoteLenMode(engine_lib.NoteLenMode.ProjectGrid) end); + if reaper.ImGui_IsItemHovered(ctx, reaper.ImGui_HoveredFlags_DelayNormal()) then + reaper.ImGui_SetTooltip(ctx, "Use the project's grid conf") + end + + ButtonGroupImageButton('note_len_mode_igrid', nlm == engine_lib.NoteLenMode.ItemConf, function() engine_lib.setNoteLenMode(engine_lib.NoteLenMode.ItemConf) end); + if reaper.ImGui_IsItemHovered(ctx, reaper.ImGui_HoveredFlags_DelayNormal()) then + reaper.ImGui_SetTooltip(ctx, "Use the MIDI item's own conf\n\n('Notes' at the bottom of the MIDI editor)") end reaper.ImGui_SameLine(ctx); reaper.ImGui_Dummy(ctx,10,0); reaper.ImGui_SameLine(ctx); - local nmod = engine_lib.getNoteLenModifier(); + if nlm == engine_lib.NoteLenMode.OSS then - ButtonGroupImageButton('note_dotted', nmod == engine_lib.NoteLenModifier.Dotted, function() - if nmod == engine_lib.NoteLenModifier.Dotted then - engine_lib.setNoteLenModifier(engine_lib.NoteLenModifier.Streight); - else - engine_lib.setNoteLenModifier(engine_lib.NoteLenModifier.Dotted); - end + local nl = engine_lib.getNoteLen(); + for s,k in ipairs({ "1", "1_2", "1_4", "1_8", "1_16", "1_32", "1_64" }) do + ButtonGroupImageButton('note_'.. k, nl==k, + function() + engine_lib.setNoteLen(k) + end + ); end - ); - ButtonGroupImageButton('note_triplet', nmod == engine_lib.NoteLenModifier.Triplet, function() - if nmod == engine_lib.NoteLenModifier.Triplet then - engine_lib.setNoteLenModifier(engine_lib.NoteLenModifier.Streight); - else - engine_lib.setNoteLenModifier(engine_lib.NoteLenModifier.Triplet); + + reaper.ImGui_SameLine(ctx); + reaper.ImGui_Dummy(ctx,10,0); + reaper.ImGui_SameLine(ctx); + + 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 + end + ); + 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 end + ); + 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 + ); + + if nmod == engine_lib.NoteLenModifier.Tuplet then + + reaper.ImGui_SameLine(ctx); + reaper.ImGui_Dummy(ctx,10,0); + reaper.ImGui_SameLine(ctx); + + local combo_items = { '4', '5', '6', '7', '8', '9', '10', '11', '12' } + + reaper.ImGui_PushStyleVar(ctx, reaper.ImGui_StyleVar_FramePadding(), 5, 4); + reaper.ImGui_SetCursorPosY(ctx, reaper.ImGui_GetCursorPosY(ctx) - 3); + reaper.ImGui_PushID(ctx, "nlet_combo"); + + local tuplet = engine_lib.getTupletDivision(); + + reaper.ImGui_SetNextItemWidth(ctx,50); + if reaper.ImGui_BeginCombo(ctx, '', tuplet) then + for i,v in ipairs(combo_items) do + local is_selected = (combo_preview_value == v); + if reaper.ImGui_Selectable(ctx, combo_items[i], is_selected) then + engine_lib.setTupletDivision(tonumber(v)); + end + if is_selected then + reaper.ImGui_SetItemDefaultFocus(ctx) + end + end + reaper.ImGui_EndCombo(ctx) + end + reaper.ImGui_PopStyleVar(ctx,1); + reaper.ImGui_PopID(ctx); end - ); + + + elseif nlm == engine_lib.NoteLenMode.ProjectGrid then + ImGui_ProjectGridLabel(ctx); + elseif nlm == engine_lib.NoteLenMode.ItemConf then + ImGui_ItemGridLabel(ctx,take); + end reaper.ImGui_PopStyleVar(ctx,3); @@ -374,18 +603,22 @@ function updateToolbarButtonState(v) end function loop() + local engine_ret = engine_lib.atLoop(); if engine_ret == -42 then - reaper.ShowMessageBox("Could not install One Small Step's helper FX on the track.\n\nIf you just installed One Small Step, please try to restart REAPER to let it refresh its JFSX repository.", "Oops !", 0); + reaper.ShowMessageBox("Could not install One Small Step's helper FX on the track.\n\nIf you've just installed One Small Step, please try to restart REAPER to let it refresh its JFSX repository.", "Oops !", 0); return; end ui_loop(); end -function stop() +function onReaperExit() updateToolbarButtonState(0); +end + +function stop() reaper.ImGui_DestroyContext(ctx); engine_lib.atExit(); end @@ -393,6 +626,7 @@ end function start() updateToolbarButtonState(1); engine_lib.atStart(); + reaper.atexit(onReaperExit); reaper.defer(loop); end diff --git a/MIDI Editor/talagan_OneSmallStep/images/note_len_mode_igrid.lua b/MIDI Editor/talagan_OneSmallStep/images/note_len_mode_igrid.lua new file mode 100644 index 000000000..c03b8a8a5 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/note_len_mode_igrid.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\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_oss.lua b/MIDI Editor/talagan_OneSmallStep/images/note_len_mode_oss.lua new file mode 100644 index 000000000..2210013a6 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/note_len_mode_oss.lua @@ -0,0 +1,24 @@ +-- @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\x02\x4C\x49\x44\x41\x54\x48\x89\xE5\xD6\x4B\x88\x8F\x51\x18\xC7\xF1\xCF\xA0\xD9\x18\x2B\x97\x9A\z +\x18\x97\x58\x91\xA1\x66\x61\x87\x66\xB2\x20\xAC\x26\x45\x6C\x28\x8A\xA9\x91\x30\x25\x11\x93\x72\x59\x8C\x1A\x53\xCA\x65\x37\x2B\x16\x2E\x53\x28\x97\x98\x94\x88\z +\x85\x59\x52\x6E\x23\x93\x26\x3B\xCA\x24\x63\x71\xCE\x34\xEF\xFF\xCC\xFF\x9D\xFF\x8B\x32\x0B\xBF\xCD\xF3\x9E\xE7\x9C\xF7\x7C\xDF\xF7\x39\xCF\x79\xCE\xA9\x1A\x1E\z +\x1E\x36\x11\x9A\x34\x21\xD4\xFF\x12\x3C\x25\x75\x0C\x0D\x0D\x8D\x37\x7E\x26\xD6\xA3\x01\xB5\xA8\xC2\x27\xBC\xC0\x4D\x7C\xCE\x7B\xB1\xBA\xBA\x7A\x7C\x70\x8E\xE6\z +\xA2\x13\x1B\x2B\x8C\xEB\x41\x0B\xDE\x55\x9A\xB0\x48\xA8\x0F\xC7\x89\x2A\x41\x09\xD1\x78\x8B\xBD\x7F\x0B\xBE\x88\x76\x3C\x29\x00\xCD\xAA\x03\x67\xFF\x14\x7C\x08\z +\x3B\xB0\x02\x5F\x2A\x80\xBE\xE3\x69\xB4\x23\x6A\xC5\xFE\xDF\x05\x2F\xC1\x09\xAC\xC5\x57\xAC\xAB\x00\xEE\x8E\x1F\xD8\x9A\xF8\xCF\x60\xF1\xEF\x80\x2F\xE1\x0D\x6E\z +\x63\x4F\x05\x28\xF4\x46\x7B\xC1\xD8\xCC\x3E\x5A\x14\x5C\x27\x7C\xFD\xBE\xD8\x5E\x5E\x00\x3C\x39\xDA\x9F\xF8\x96\xF4\x6D\xC2\x9C\x22\xE0\xE6\x68\xAF\x45\x3B\xBD\z +\xCC\x98\xBB\x78\x9F\x69\x37\x45\xBB\x1D\xF3\xCB\x8C\x6F\x4A\x1D\xE5\xC0\xAB\x94\xEE\xC3\x1F\x49\x7F\x0F\xD6\x60\x67\xC6\xB7\x19\x43\x42\xA8\xCB\x69\x69\x11\xF0\z +\x02\xA5\x7F\xF3\x31\xE9\xBF\x11\xED\x1D\xF4\xC7\xE7\x5B\xA8\xC6\xEA\x1C\x70\x6D\x11\x70\xAA\x67\x49\x7B\x5A\xE6\x79\x20\xDA\x59\xD1\xD6\x17\x98\x2F\x17\xFC\x56\z +\x28\x91\x23\xBA\x9E\xF4\x6F\x11\x6A\xF6\x6E\x2C\x8B\xBE\x06\x21\x4A\x27\x73\x38\x03\xA9\xA3\x1C\xF8\x21\xE6\x65\xDA\x4F\x71\x2F\xD3\x6E\x10\xB6\xCC\x41\x7C\xC8\z +\xF8\xEB\x50\x93\x03\x7E\x59\x04\x7C\x35\xDA\xE6\x8C\xAF\x2D\x19\xD3\x21\x64\xEF\xF1\x1C\x50\xAA\xFB\x45\xC0\xEF\x85\xBF\x3C\x9D\xF1\x3D\x57\x5A\x95\x36\x44\x5B\z +\xB6\x2A\x25\xBA\xA2\x34\x32\xA0\x2A\xBD\x73\xC5\xF3\x78\xA9\x10\x9E\x16\x74\x65\xBA\x0F\xE2\x54\x01\x58\x56\xF5\xE8\x4B\xCF\xE3\xBC\xAC\xEE\xC3\x11\x9C\x43\x63\z +\xC6\x7F\x1A\x2B\x31\x58\x10\xDA\x16\xE7\x1A\xA3\xF1\xB6\x53\x3B\x2E\x0B\x89\xB5\x2B\xE3\xEF\x15\xB2\x7A\x2B\x1E\x19\x2D\x91\x83\x4A\xEB\x74\x97\xD2\xE5\x2A\x0C\z +\x26\x1C\x8B\xC7\x70\x5E\x28\x24\xD9\xBF\xEF\x16\xAA\xDC\x54\xA1\xAC\x76\x1A\xDD\xCF\x07\x84\x65\xCA\x55\xDE\x1A\xA7\x5A\x24\x9C\x54\x0B\x63\xFB\x15\x5E\x0B\xE5\z +\x74\x86\x90\x13\x35\x78\x8C\x6D\xC2\xC9\x56\xA2\x74\x8D\x8B\x82\x47\x34\x5B\x88\x42\xA3\xB0\x6F\xAB\x84\x8C\x7D\x20\xDC\x56\xFA\xF3\x5E\xAC\x08\xFE\x57\xFA\xFF\z +\x2E\xF4\x13\x06\xFE\x05\xC3\xB2\x80\x27\x57\x8C\xEE\x16\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 new file mode 100644 index 000000000..d65e32150 --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/note_len_mode_pgrid.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\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" +; diff --git a/MIDI Editor/talagan_OneSmallStep/images/note_tuplet.lua b/MIDI Editor/talagan_OneSmallStep/images/note_tuplet.lua new file mode 100644 index 000000000..bf88ace4d --- /dev/null +++ b/MIDI Editor/talagan_OneSmallStep/images/note_tuplet.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\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\xE2\x49\x44\x41\x54\x48\x89\xED\x96\x3D\x0A\xC2\x40\x10\x46\x5F\xC4\x76\x8A\x74\x01\xBB\x5C\z +\x21\xA5\x90\xCA\x1C\xC1\x1C\xC1\x33\xE4\x08\xE6\x0A\x39\x82\x5E\xC1\x2A\x60\xE9\x11\x4C\x27\xA4\x4B\x31\x07\x88\x45\x56\x10\x0C\xE8\xF8\x43\x0A\xF7\xAB\x76\x60\z +\x66\xDE\xCE\xC7\xB2\xBB\x41\xDF\xF7\x4C\xA1\xD9\x24\x54\x0F\xF6\x60\x0F\xF6\xE0\x4F\x34\xB7\x24\xAB\x6A\x0C\x9C\x5D\x58\x00\x31\xB0\x01\x0A\x11\x29\x2D\xBD\x4C\z +\x13\x8B\x48\x03\x64\x2E\x8C\x81\x13\x70\x70\x6B\x93\x46\x27\xBE\xB4\xED\xE8\xCB\xB1\x88\xA2\x00\x48\x80\x0E\xE8\x44\xA4\x52\xD5\x2D\xB0\x7F\xA1\xEE\x39\x18\xE0\z +\x58\xD7\x0F\xC9\x79\x9E\x03\xAC\x1D\xB8\x54\xD5\x04\x08\x6F\xE0\xB1\x9A\x65\x9A\x8E\x6E\xC6\x64\xB5\xAA\x86\x0C\x13\x97\x22\xD2\x01\x2B\x06\xBB\x13\x4B\x1F\x33\z +\x98\xE1\x20\x35\x22\x52\xB9\x38\x01\x1A\x06\x17\x4C\x0A\x2C\x1F\x01\x55\xDD\x39\x70\x71\x17\xC7\x40\xE6\x1C\xF8\x0D\xF8\x9B\xFA\xBF\x9B\xCB\x83\x3D\xD8\x83\x3D\z +\xF8\x6D\x5D\x01\x75\x01\x41\x78\x66\xDC\x48\x8D\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82" +; diff --git a/MIDI Editor/talagan_OneSmallStep/talagan_OneSmallStep Engine lib.lua b/MIDI Editor/talagan_OneSmallStep/talagan_OneSmallStep Engine lib.lua index f5ad6af3b..606e03bfa 100644 --- a/MIDI Editor/talagan_OneSmallStep/talagan_OneSmallStep Engine lib.lua +++ b/MIDI Editor/talagan_OneSmallStep/talagan_OneSmallStep Engine lib.lua @@ -21,6 +21,12 @@ local noteLenLookup = { ["1_64"] = {next="1_32", prec="1_64", qn=0.0625 } }; +local NoteLenMode = { + OSS=0, + ProjectGrid=1, + ItemConf=2 +} + local InputMode = { None=0, Pedal=1, @@ -31,7 +37,8 @@ local InputMode = { local NoteLenModifier = { Straight=0, Dotted=1, - Triplet=2 + Triplet=2, + Tuplet=3 } @@ -39,6 +46,8 @@ local function DBG(m) --reaper.ShowConsoleMsg(m .. "\n"); end +----------- + local function setMode(m) reaper.SetExtState("OneSmallStep", "Mode", tostring(m), true) end @@ -46,8 +55,27 @@ local function getMode() return tonumber(reaper.GetExtState("OneSmallStep", "Mode")) or 0; end +----------- + +local function setNoteLenMode(m) + reaper.SetExtState("OneSmallStep", "NoteLenMode", tostring(m), true) +end +local function getNoteLenMode() + return tonumber(reaper.GetExtState("OneSmallStep", "NoteLenMode")) or 0; +end + +----------- + +local function setTupletDivision(m) + reaper.SetExtState("OneSmallStep", "TupletDivision", tostring(m), true) +end +local function getTupletDivision() + return tonumber(reaper.GetExtState("OneSmallStep", "TupletDivision")) or 4; +end + +----------- + local function setNoteLen(str) - -- Persist the param reaper.SetExtState("OneSmallStep", "NoteLen", str, true); end local function getNoteLen() @@ -58,6 +86,8 @@ local function getNoteLen() return nl; end +----------- + local function setNoteLenModifier(m) reaper.SetExtState("OneSmallStep", "NoteLenModifier", tostring(m), true); end @@ -65,6 +95,7 @@ local function getNoteLenModifier() return tonumber(reaper.GetExtState("OneSmallStep", "NoteLenModifier")); end local function getNoteLenModifierFactor() + local m = getNoteLenModifier(); if m == NoteLenModifier.Straight then @@ -73,6 +104,9 @@ local function getNoteLenModifierFactor() return 1.5; elseif m == NoteLenModifier.Triplet then return 2/3.0; + elseif m == NoteLenModifier.Tuplet then + local div = getTupletDivision(); + return 2.0/div; end return 1.0; @@ -89,7 +123,8 @@ local function decreaseNoteLen() end local function getNoteLenQN() - local nl = getNoteLen(); + local nl = getNoteLen(); + return noteLenLookup[nl].qn; end @@ -170,18 +205,44 @@ local function TakeForEdition() return nil end --- Commits the currently held notes into the take -local function commit(take, notes) - --[[ - local grid_len, swing, note_len = reaper.MIDI_GetGrid(take); +local function resolveNoteLenQN(take) - if note_len == 0 then - note_len = grid_len; + local nlm = getNoteLenMode(); + + if nlm == NoteLenMode.OSS then + return getNoteLenQN() * getNoteLenModifierFactor(); + elseif nlm == NoteLenMode.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 - local note_len = getNoteLenQN() * getNoteLenModifierFactor(); +-- Commits the currently held notes into the take +local function commit(take, notes) + + local note_len = resolveNoteLenQN(take); local noteStartTime = reaper.GetCursorPosition() local noteStartQN = reaper.TimeMap2_timeToQN(0, noteStartTime) @@ -203,6 +264,20 @@ local function commit(take, notes) reaper.UpdateItemInProject(mediaItem) reaper.SetEditCurPos(noteEndTime, false, false); reaper.MarkTrackItemsDirty(track, mediaItem) + + -- Grow the midi item + local itemStartTime = reaper.GetMediaItemInfo_Value(mediaItem, "D_POSITION") + local itemLength = reaper.GetMediaItemInfo_Value(mediaItem, "D_LENGTH") + local itemEndTime = itemStartTime + itemLength; + + if(itemEndTime >= noteEndTime) then + return + end + + local itemStartQN = reaper.TimeMap2_timeToQN(0, itemStartTime) + local itemEndQN = reaper.TimeMap2_timeToQN(0, noteEndTime) + + reaper.MIDI_SetItemExtents(mediaItem, itemStartQN, itemEndQN) end -------------------------------------------------------------------- @@ -316,8 +391,7 @@ local function listenToEvents(called_from_action) local oss_state = helper_lib.oneSmallStepState(track); if mode == InputMode.Pedal then - if oss_state.pedalActivity > 0 then - + if oss_state.pedalActivity > 0 or called_from_action then -- Pedal event, commit new notes reaper.Undo_BeginBlock(); -- Acknowledge the pedal @@ -325,6 +399,7 @@ local function listenToEvents(called_from_action) commit(take, oss_state.pitches); reaper.Undo_EndBlock("One Small Step - Add notes on pedal event",-1); end + elseif mode == InputMode.Action then if called_from_action then reaper.Undo_BeginBlock(); @@ -351,14 +426,11 @@ local function listenToEvents(called_from_action) end end - if oss_state.pedalActivity > 0 then - -- Allow the use of the pedal in keyboard mode - -- To insert rests + -- Allow the use of the action, but only insert rests + if called_from_action then reaper.Undo_BeginBlock(); - -- Acknowledge the pedal - helper_lib.resetPedalActivity(track); - commit(take, {} ); - reaper.Undo_EndBlock("One Small Step - Add rest on pedal event",-1); + commit(take, {}) ; + reaper.Undo_EndBlock("One Small Step - Add rest on action",-1); end end @@ -394,12 +466,19 @@ end return { -- Enums InputMode = InputMode, + NoteLenMode = NoteLenMode, NoteLenModifier = NoteLenModifier, --Functions setMode = setMode, getMode = getMode, + setNoteLenMode = setNoteLenMode, + getNoteLenMode = getNoteLenMode, + + setTupletDivision = setTupletDivision, + getTupletDivision = getTupletDivision, + getNoteLenModifier = getNoteLenModifier, setNoteLenModifier = setNoteLenModifier, getNoteLenModifierFactor = getNoteLenModifierFactor,