|
|
|
04-07-2016, 04:39 PM
|
#1
|
Banned
Join Date: Sep 2015
Posts: 1,650
|
[SOLVED] MIDI CC can't terminate script?
I have a new MIDI script....
https://github.com/Lazzle/ReaMIDI/bl...M%20Delete.lua
.... that I want to assign to a CC on a controller keyboard. So with a keycommand it runs and then you press the keycommand and it remembers to terminate the script, as requested the first time.
With a MIDI CC, when it is running the second press doesn't do anything. So I can turn it on, but not off.
Am I missing something?
Last edited by snooks; 05-04-2016 at 08:12 AM.
|
|
|
04-08-2016, 05:37 AM
|
#2
|
Banned
Join Date: Sep 2015
Posts: 1,650
|
Quick test script. If you assign a keycommand and a MIDI CC to this script you'll see that you can't terminate it with the MIDI CC, but you can with the KC. The behaviour should really be the same.
Code:
a=0
function loop()
a=a+1
if a>100 then a=100 end
reaper.defer(loop)
end
function exit()
if terminating==true then reaper.ShowConsoleMsg("exiting.. \n") end
end
terminating=false
reaper.atexit(exit)
terminating=true
reaper.ShowConsoleMsg("\nstarting\n")
loop()
|
|
|
05-02-2016, 03:35 PM
|
#3
|
Banned
Join Date: Sep 2015
Posts: 1,650
|
* bump *
This is a bug-like thing, right?
|
|
|
05-03-2016, 11:08 AM
|
#4
|
Human being with feelings
Join Date: Aug 2015
Posts: 3,671
|
i wish i could help you with your problem snooks, but i wanted to drop a comment in this thread...
i've been wanting this feature ever since i moved away from sequencing on my MPC into sequencing full time in REAPER. this is HUGE for people who want to compose and edit a time selected loop from the controller. mouse-free sequencing. thank you so much, i will be following your work.
someone please help this guy!
|
|
|
05-03-2016, 12:21 PM
|
#5
|
Human being with feelings
Join Date: Aug 2012
Location: Finland
Posts: 2,668
|
Maybe reaper.get_action_context() would help?
Test:
(terminates if MIDI CC 7 value is 0, otherwise defer)
Code:
local val = -1
local last_val = -1
reaper.ShowConsoleMsg("\nstarting\n")
function loop()
is_new_value,filename,sectionID,cmdID,mode,resolution,val = reaper.get_action_context()
if val ~= last_val then
reaper.ShowConsoleMsg(tostring(val) .. "\n")
last_val = val
end
if val > 0 then
reaper.defer(loop)
end
end
function exit()
if terminating==true then reaper.ShowConsoleMsg("exiting.. \n") end
end
terminating=false
reaper.atexit(exit)
terminating=true
loop()
|
|
|
05-03-2016, 12:25 PM
|
#6
|
Human being with feelings
Join Date: Aug 2012
Location: Finland
Posts: 2,668
|
|
|
|
05-04-2016, 04:52 AM
|
#7
|
Banned
Join Date: Sep 2015
Posts: 1,650
|
Yes, that works.... thanks spk77! For just toggling with learnt MIDI CCs or notes this is all that is needed....
Code:
reaper.ShowConsoleMsg("\nstarting\n")
function loop()
if reaper.get_action_context() then return end
reaper.defer(loop)
end
function exit()
if terminating==true then reaper.ShowConsoleMsg("exiting.. \n") end
end
terminating=false
reaper.atexit(exit)
terminating=true
reaper.get_action_context() -- to clear "is_new_value" for checking in loop
loop()
@mccrabney: cheers for the shout, that's the new version uploaded if you want to test it out...
https://github.com/Lazzle/ReaMIDI/bl...M%20Delete.lua
... it leaves behind the input FX it adds at the moment because removing it by changing the track chunk causes glitches in audio and the remove FX thing in SWS doesn't work with input FX. Not a big deal, but it makes my janitorial genes a bit twitchy.
|
|
|
05-04-2016, 10:37 AM
|
#8
|
Human being with feelings
Join Date: Aug 2015
Posts: 3,671
|
interesting. won't have an opportunity to test today but i look forward to it. i haven't seen a script that adds a js fx in this manner, very cool.
are additional instances of this js fx added if this script is triggered multiple times?
----
unrelated but i have another script suggestion that is kind of in line with this type of script: a script that selects the most recently recorded notes in a midi item.
for instance: you have a hi hat pattern in a midi item. you overdub in kicks and snares and want to quantize them but not the hi hats. ideally, the kick and snare notes would automatically be selected once overdub is turned off so they could be selectively quantized without having to be manually selected first.
|
|
|
05-04-2016, 11:32 AM
|
#9
|
Banned
Join Date: Sep 2015
Posts: 1,650
|
Quote:
Originally Posted by mccrabney
interesting. won't have an opportunity to test today but i look forward to it. i haven't seen a script that adds a js fx in this manner, very cool.
|
That's inspired by eugen2777 who uses something similar to create a track for his retrospective record script. It does add a new layer of possibilities to scripting.
Quote:
are additional instances of this js fx added if this script is triggered multiple times?
|
Have no fear, it checks if one is there and adds one if not or re-enables the existing one if it exists, then disables it (again) on exit. The untidyness bit is having the disabled JS in the input FX bin when I'd really like to delete it. Maybe spk77 will swing by in a minute and reveal another bit of the API I haven't read though.
Quote:
unrelated but i have another script suggestion that is kind of in line with this type of script: a script that selects the most recently recorded notes in a midi item.
for instance: you have a hi hat pattern in a midi item. you overdub in kicks and snares and want to quantize them but not the hi hats. ideally, the kick and snare notes would automatically be selected once overdub is turned off so they could be selectively quantized without having to be manually selected first.
|
That would be useful, let me stew on it for a while.
|
|
|
05-05-2016, 10:46 AM
|
#10
|
Human being with feelings
Join Date: Aug 2015
Posts: 3,671
|
hey snooks - i'm having strange behavior with this one.
i assigned it to a cc (fader on my quneo)
i recorded some midi notes to a midi file on a short loop
i then trigger the script, and i lose all transport control (unresponsive to kb or midi-assigned transport actions) and i cannot click around in REAPER. it's as if focus is stolen by some offscreen dialog box.
more testing will be posted in an edit or a reply...
|
|
|
05-05-2016, 12:10 PM
|
#11
|
Banned
Join Date: Sep 2015
Posts: 1,650
|
It's supposed to be triggered with a single CC message (or note) so a slider would turn it on and off lots of times. I don't know what effect that would have. Maybe it's something else, but learning a button sending a note/CC would be best.
|
|
|
05-05-2016, 03:53 PM
|
#12
|
Human being with feelings
Join Date: Aug 2015
Posts: 3,671
|
gotcha. i tried using using another cc sending only 0 and 127 messages and got the same behavior. how have you learned this cc to your script -- absolute, relative, etc?
|
|
|
05-05-2016, 04:33 PM
|
#13
|
Banned
Join Date: Sep 2015
Posts: 1,650
|
The CC is learned in absolute mode and the button only sends 127. I've also tested with an APC40 Mini which sends notes. This is strange, it works here with no weirdness.
Is this a portable install in Program Files by any chance? I'm thinking that because it is trying to write to the resource path there might be some permissions issue there if the resource path is in a protected area.
edit: oh, yeah I attached a file to show the tooltip that should come up when it's active...
|
|
|
05-06-2016, 09:41 AM
|
#14
|
Human being with feelings
Join Date: Aug 2015
Posts: 3,671
|
ugh, i'm an idiot, i somehow managed to save what looks like an html file as "DM Delete.lua"
sorry, snooks. let me try again.
edit, ok it's working. you are a rockstar.
some notes, coming from someone who used an MPC as primary midi sequencer from 2008-2014 before switching to REAPER as mentioned before (and who also beta tested extensively for the mpc1000/2500 3rd party "jj" os)
this behaves almost exactly the way i would hope, and i can do a lot of the rest myself. however, i would consider this perfect if instead of turning on and off with 127 values, it turned on at 127 and off at 0, so that "toggle" buttons or "hold and release" buttons could be used here.
i have assigned this script to a button on my launchpad that sends 127 when on and 0 when released. i envision holding the button down with one hand and deleting notes with the other hand. granted, i could remap value 0 messages to value 127 messages, but then you run into potential problems where the on/off gets out of sync with the launchpad. right now, this is the solution i'm using and it works OK. will report back if it becomes a problem, otherwise, i guess we're good!
i really like that this script doesn't turn on Overdub by default like it did in the MPC series.
you've made my year with this. THANK YOU. please point me toward any donation site or PM me a paypal address so i can tip you.
Last edited by mccrabney; 05-06-2016 at 10:04 AM.
|
|
|
05-06-2016, 06:40 PM
|
#15
|
Banned
Join Date: Sep 2015
Posts: 1,650
|
No worries, I've uploaded another version that should do what you want. I haven't tested it though so maybe it doesn't.
|
|
|
06-29-2016, 08:18 PM
|
#16
|
Human being with feelings
Join Date: Aug 2015
Posts: 3,671
|
any chance you can make a version of this that SELECTS the note rather than DELETES it?? adding to previous selection so you could select notes as it loops and then selectively quantize them......
|
|
|
06-30-2016, 08:39 AM
|
#17
|
Banned
Join Date: Sep 2015
Posts: 1,650
|
Yes, no problemo - I'll do it over the next couple/few days.....
|
|
|
06-30-2016, 08:45 AM
|
#18
|
Human being with feelings
Join Date: Aug 2015
Posts: 3,671
|
amazing, thanks. i might like this one even more than the original DM delete script...
|
|
|
07-29-2016, 07:53 AM
|
#19
|
Human being with feelings
Join Date: Aug 2015
Posts: 3,671
|
yo, checking in about the above request...
also a question -- for the original DM delete script, while the script is running, is there a way to block the Note On from reaching the VST? when i'm attempting to DM delete notes from a sequence, i hear the note that i'm deleting get triggered on NOTEON. in the world of MPCs, the NOTEON is blocked from triggering the sample, but rather acts as a "flag" to block/delete subsequent instances of that note from triggering noteon.
|
|
|
07-29-2016, 09:32 AM
|
#20
|
Banned
Join Date: Sep 2015
Posts: 1,650
|
Sorry, I totally forgot about that... here's an edited script, you change the line...
Code:
local action = edit_types.DELETE
... to edit_types.SELECT if you want to select instead of delete.
I think anyway, I haven't tested it yet... I will later if there are any problems.
Code:
-- D(rum) M(achine) Delete
-- run script and held notes will be deleted from
-- either the active item in the MIDI editor or
-- on an item between the loop cursors of a the
-- first selected track, which must be rec-armed.
-- run script again to get out of delete mode
local function DBG(str)
--reaper.ShowConsoleMsg(str.."\n")
end
local edit_types={DELETE="Delete", SELECT="Select"}
local action = edit_types.DELETE;
jsfx={} --store details of helper effect
jsfx.name="Script Note Getter"
jsfx.fn="Script Note Getter"
--jsfx.body at end of script
function createJSEffect(fn,str)
local file=io.open(reaper.GetResourcePath().."/Effects/"..fn, "w")
file:write(str)
file:close()
end
function deleteJSEffect(fx)
os.remove(reaper.GetResourcePath().."/Effects/"..fx.fn)
end
--fx is table with .name and .fn (for filename)
function removeJSEffect(track,fx)
local chunk,ok="",false
ok,chunk=reaper.GetTrackStateChunk(track,chunk, false)
local pattern="(BYPASS %d %d %d[%c%s].JS \""..fx.name..".-WAK %d)"
local replacements
chunk,replacements=string.gsub(chunk,pattern,"")
if replacements>0 then
ok=reaper.SetTrackStateChunk(tr,chunk,false)
deleteJSEffect(fx)
return true
end
return false
end
function getOrAddInputFx(track,fx,create_new)
local idx=reaper.TrackFX_AddByName(track,fx.name,true,1)
if idx==-1 or idx==nil then
idx=reaper.TrackFX_AddByName(track,fx.fn,true,1)
if (idx==nil or idx==-1) and create_new==true then
createJSEffect(fx.fn,fx.body)
idx=getOrAddInputFx(track,fx,false)
return idx
else
tr=nil
return -1
end
end
idx=idx|0x1000000
reaper.TrackFX_SetEnabled(track, idx, true)
return idx
end
local delete_ahead=0.15 --so that notes don't sound
function getNotes(tk,pitches,pp_qn,check_start,l_start)
local ni, tr, it
local midi={}
cnt=0
local ok, sel, mute, startpos, endpos, chan, pitch, vel=reaper.MIDI_GetNote(tk, 0)
while ok do
for i=1,#pitches,1 do
if pitch==pitches[i] then
startpos=reaper.MIDI_GetProjQNFromPPQPos(tk, startpos)
endpos=reaper.MIDI_GetProjQNFromPPQPos(tk, endpos)
if (startpos<=pp_qn+delete_ahead and endpos>=pp_qn) or
(check_start and startpos>=l_start and startpos<=l_start+delete_ahead) then
local note={ type="note", idx=cnt, -- 6
select=sel,mute=mute, ostartpos=startpos, --12
startpos=startpos, endpos=endpos, len=endpos-startpos,
pitch=pitch, chan=chan, vel=vel }
midi[#midi+1]=note
end
end
end
cnt=cnt+1
ok, sel, mute, startpos, endpos, chan, pitch, vel=reaper.MIDI_GetNote(tk, cnt)
end
return midi
end
function dMedit()
local is_new_value,_,_,_,_,_,val=reaper.get_action_context()
if is_new_value and val==0 then return end
-- tr, tk, helper_idx set in prep()
-- get number of held notes from helper plugin
nib=reaper.TrackFX_GetParam(tr, helper_idx, 1) --1=note in buffer
if nib>0 then
-- get loop points and check whether cursor is near the end
-- so we can delete on return to start of loop without them
-- playing
local l_start, l_end=reaper.GetSet_LoopTimeRange(false, false, 0, 0, false)
l_start=reaper.TimeMap2_timeToQN(0, l_start)
l_end=reaper.TimeMap2_timeToQN(0, l_end)
local pp=reaper.GetPlayPosition()
local pp_qn=reaper.TimeMap2_timeToQN(0, pp)
local check_start=l_end-pp_qn<delete_ahead and true or false
--get held notes from buffer in helper plugin
local pitches={}
for i=1,nib,1 do
reaper.TrackFX_SetParam(tr,helper_idx,2,i-1) --set Note# to i
pitches[#pitches+1],_,_=reaper.TrackFX_GetParam(tr, helper_idx, 3)
end
local notes=getNotes(tk,pitches,pp_qn,check_start,l_start)
if #notes>0 then
DBG("Start "..action.." notes...")
reaper.Undo_BeginBlock() -- create undo point for these notes
--always go backwards deleting notes
for i=#notes,1,-1 do
if action == edit_types.SELECT then
reaper.MIDI_SetNote(tk, notes[i].idx, true, nil, nil, nil, nil, nil, nil, nil)
else
reaper.MIDI_DeleteNote(tk,notes[i].idx)
end
end
reaper.Undo_EndBlock("DM "..action.." - ".. action.. " notes",4)
end
reaper.UpdateArrange()
end
reaper.defer(dMedit)
end
function getMidiEditorTrackTake()
local ame=reaper.MIDIEditor_GetActive()
local mode=reaper.MIDIEditor_GetMode(ame)
if mode > -1 then -- we are in a MIDI editor, -1 if ME not focused
tk=reaper.MIDIEditor_GetTake(ame)
--check that it's an actual take (in case of empty MIDI editor)
if not reaper.ValidatePtr(tk, 'MediaItem_Take*') then return nil,nil end
tr=reaper.GetMediaItemTake_Track(tk)
else
return nil,nil
end
return tr,tk
end
function prep()
DBG("in prep")
reaper.get_action_context() -- to clear is_new_value for checking
-- for new presses in main loop
tr,tk=getMidiEditorTrackTake()
if tk==nil then
if reaper.CountSelectedTracks()>0 then
tr=reaper.GetSelectedTrack(0,0)
local _,t_name=reaper.GetSetMediaTrackInfo_String(tr,"P_NAME"," ",false)
local _, ts=reaper.GetTrackState(tr)
if ts&64==64 and ts&2==2 then -- is rec armed and selected
local num_items=reaper.CountTrackMediaItems(tr)
if num_items>0 then
local l_start,l_end=reaper.GetSet_LoopTimeRange(false,true,0,0,true)
local cur=reaper.GetCursorPosition()
local i=1
while i<=num_items do
local it=reaper.GetTrackMediaItem(tr,i-1)
local i_start=reaper.GetMediaItemInfo_Value(it,"D_POSITION")
if math.floor(l_start*10)==math.floor(i_start*10) then
tk=reaper.GetActiveTake(it)
i=num_items
end
i=i+1
end
end
end
end
end
if tk~=nil and reaper.BR_IsTakeMidi(tk) then
helper_idx=getOrAddInputFx(tr,jsfx,true)
DBG("helper_idx="..helper_idx)
if helper_idx>-1 then
reaper.TrackCtl_SetToolTip("!-!-!-!-!-! Live "..action.." ACTIVE !-!-!-!-!-!", 800,20, true)
dMedit()
else
DBG("No effect added")
end
end
end
function cleanUp()
if helper_idx~=nil then
reaper.TrackCtl_SetToolTip("--- Live "..action.." Inactive ---", 800,20, true)
DBG("exit")
--removeJSEffect(tr,jsfx) --set chunk causes glitches
--so can't remove input FX
reaper.TrackFX_SetEnabled(tr, helper_idx, false) --just disable it
end
end
jsfx.body=[[
desc:Script Note Getter
slider1:0<0,1,1{On,Off}>Active (eats notes)
slider2:0<0,127,1>Notes in buffer
slider3:0<0,1000,1>Note # (for script)
slider4:0<0,127,1>Output Pitch
slider5:0<0,1,1>Trigger
@init
notebuf=0; //start pos of buffer
nb_width=3; //number of entries per note
buflen=0; //notes in buffer
function addRemoveNoteFromBuffer(m1,m2,m3)
(
s = m1&$xF0;
c = m1&$xF; // channel
n = m2;
v = m3; // velocity
init_buflen=buflen;
i = -1;
while // look for this note|channel already in the buffer
(
i = i+1;
i < buflen && (notebuf[nb_width*i]|0 != n || notebuf[nb_width*i+1]|0 != c);
);
(s == $x90 && v > 0) ? // note-on, add to buffer
(
notebuf[nb_width*i] = n;
notebuf[nb_width*i+1] = c;
notebuf[nb_width*i+2] = v;
i == buflen ? buflen = buflen+1;
)
: // note-off, remove from buffer
(
is_note_off=1;
i < buflen ?
(
memcpy(notebuf+nb_width*i, notebuf+nb_width*(i+1),
nb_width*(buflen-i-1)); // delete the entry
buflen = buflen-1;
);
);
buflen==init_buflen ? -1; //return value for nothing added/removed
);
@slider
p=slider3*nb_width; //position in buffer
slider4=notebuf[p];
@block
while (midirecv(offset,msg1,msg2,msg3))
(
slider1 ? (
midisend(offset,msg1,msg2,msg3);
):( //eating notes
msg1|$x90==$x90 ? (
addRemoveNoteFromBuffer(msg1,msg2,msg3);
);
msg1|$x80==$x80 ? (
addRemoveNoteFromBuffer(msg1,msg2,msg3)==-1 ? (
//no note in buffer, so allow trailing note-offs through
midisend(offset,msg1,msg2,msg3);
);
);
slider2=buflen;
);
)
]]
script_init=true
reaper.atexit(cleanUp)
script_init=false
reaper.Undo_BeginBlock()
prep()
reaper.Undo_EndBlock("DM Delete",-1)
It shouldn't be allowing any input notes through after the script is active..... I'll have a look at that l8tr too.
|
|
|
07-29-2016, 12:26 PM
|
#21
|
Human being with feelings
Join Date: Aug 2015
Posts: 3,671
|
thanks dude! awesome work, now to make space for a quantize button on my launchpad pro layout...
|
|
|
07-29-2016, 05:18 PM
|
#22
|
Banned
Join Date: Sep 2015
Posts: 1,650
|
No worries, could you explain what's happening with Note Ons getting through... is it ones you are pressing or ones in a sequence? If it's from the sequence there's a lookahead value in the script...
Code:
local delete_ahead=0.15 --so that notes don't sound
... that works for me, anything less than that and the odd Note On gets through from the sequence. Maybe that needs set a bit bigger on your system?
|
|
|
08-01-2016, 09:00 AM
|
#23
|
Human being with feelings
Join Date: Aug 2015
Posts: 3,671
|
yeah let me try to explain further. difficult.
it's the one I'm pressing -- let's say there is a bunch of note 36s that I'm trying to delete. here are my steps:
1- trigger script
2- press/hold note 36
3- issue- note 36 is triggered at moment of step 2
this is not a functional issue, more of an "audio-cosmetic" issue. I'll need to confirm as I'm away from the equipment atm but I'm pretty sure this is that happens.
|
|
|
08-01-2016, 03:40 PM
|
#24
|
Banned
Join Date: Sep 2015
Posts: 1,650
|
It shouldn't do that, it should eat all MIDI from the track input and work or not eat all MIDI and not work. Unless there's some MIDI routing going on that's getting around the Input FX somehow...
|
|
|
08-01-2016, 04:42 PM
|
#25
|
Human being with feelings
Join Date: Aug 2015
Posts: 3,671
|
Quote:
Originally Posted by snooks
It shouldn't do that, it should eat all MIDI from the track input and work or not eat all MIDI and not work. Unless there's some MIDI routing going on that's getting around the Input FX somehow...
|
thanks, will do some analysis. i do have some nonstandard routing going on that may be at cause. sorry to raise concern.
I'm gonna have to assign this to a foot pedal in addition to a launchpad button.
|
|
|
08-10-2016, 10:22 AM
|
#26
|
Human being with feelings
Join Date: Aug 2015
Posts: 3,671
|
howdy, checking in again to mention that the newest version (with the SELECT option) doesn't seem to allow midi cc to terminate the script, as per the original question in this thread haha...it appears we've come full circle...tests OK with regular key commands, but not midi cc.
|
|
|
08-11-2016, 01:06 AM
|
#27
|
Banned
Join Date: Sep 2015
Posts: 1,650
|
Whoops, thanks for reporting. I'm MIDI-less for the next couple of days but I'll have a look to see what's happened.
|
|
|
08-13-2016, 01:43 PM
|
#28
|
Banned
Join Date: Sep 2015
Posts: 1,650
|
Okay, I've had a look/play and it seems that possibly the controller you are using to trigger the script is no longer a two state CC button? It only exits with a zero value from the learned MIDI command at the moment. But the bit of code that checks for that is a bit limiting because we don't actually have to check for a zero value (just the next one will do). Here's a version with slightly less worse comments at the top and that line fixed enhanced...
Code:
-- D(rum) M(achine) Edit
-- run script and held notes will be edited in
-- either the active item in the MIDI editor or
-- on an item between the loop cursors of a the
-- first selected track, which must be rec-armed.
-- run script again to get out of edit mode
-- edit modes are: delete
-- or select
local function DBG(str)
--reaper.ShowConsoleMsg(str.."\n")
end
local edit_types={DELETE="Delete", SELECT="Select"}
local action = edit_types.DELETE;
jsfx={} --store details of helper effect
jsfx.name="Script Note Getter"
jsfx.fn="Script Note Getter"
--jsfx.body at end of script
function createJSEffect(fn,str)
local file=io.open(reaper.GetResourcePath().."/Effects/"..fn, "w")
file:write(str)
file:close()
end
function deleteJSEffect(fx)
os.remove(reaper.GetResourcePath().."/Effects/"..fx.fn)
end
--fx is table with .name and .fn (for filename)
function removeJSEffect(track,fx)
local chunk,ok="",false
ok,chunk=reaper.GetTrackStateChunk(track,chunk, false)
local pattern="(BYPASS %d %d %d[%c%s].JS \""..fx.name..".-WAK %d)"
local replacements
chunk,replacements=string.gsub(chunk,pattern,"")
if replacements>0 then
ok=reaper.SetTrackStateChunk(tr,chunk,false)
deleteJSEffect(fx)
return true
end
return false
end
function getOrAddInputFx(track,fx,create_new)
local idx=reaper.TrackFX_AddByName(track,fx.name,true,1)
if idx==-1 or idx==nil then
idx=reaper.TrackFX_AddByName(track,fx.fn,true,1)
if (idx==nil or idx==-1) and create_new==true then
createJSEffect(fx.fn,fx.body)
idx=getOrAddInputFx(track,fx,false)
return idx
else
tr=nil
return -1
end
end
idx=idx|0x1000000
reaper.TrackFX_SetEnabled(track, idx, true)
return idx
end
local delete_ahead=0.17 --so that notes don't sound
function getNotes(tk,pitches,pp_qn,check_start,l_start)
local ni, tr, it
local midi={}
cnt=0
local ok, sel, mute, startpos, endpos, chan, pitch, vel=reaper.MIDI_GetNote(tk, 0)
while ok do
for i=1,#pitches,1 do
if pitch==pitches[i] then
startpos=reaper.MIDI_GetProjQNFromPPQPos(tk, startpos)
endpos=reaper.MIDI_GetProjQNFromPPQPos(tk, endpos)
if (startpos<=pp_qn+delete_ahead and endpos>=pp_qn) or
(check_start and startpos>=l_start and startpos<=l_start+delete_ahead) then
local note={ type="note", idx=cnt, -- 6
select=sel,mute=mute, ostartpos=startpos, --12
startpos=startpos, endpos=endpos, len=endpos-startpos,
pitch=pitch, chan=chan, vel=vel }
midi[#midi+1]=note
end
end
end
cnt=cnt+1
ok, sel, mute, startpos, endpos, chan, pitch, vel=reaper.MIDI_GetNote(tk, cnt)
end
return midi
end
function dMedit()
local is_new_value,_,_,_,_,_,val=reaper.get_action_context()
if is_new_value then return end
-- tr, tk, helper_idx set in prep()
-- get number of held notes from helper plugin
nib=reaper.TrackFX_GetParam(tr, helper_idx, 1) --1=note in buffer
if nib>0 then
-- get loop points and check whether cursor is near the end
-- so we can delete on return to start of loop without them
-- playing
local l_start, l_end=reaper.GetSet_LoopTimeRange(false, false, 0, 0, false)
l_start=reaper.TimeMap2_timeToQN(0, l_start)
l_end=reaper.TimeMap2_timeToQN(0, l_end)
local pp=reaper.GetPlayPosition()
local pp_qn=reaper.TimeMap2_timeToQN(0, pp)
local check_start=l_end-pp_qn<delete_ahead and true or false
--get held notes from buffer in helper plugin
local pitches={}
for i=1,nib,1 do
reaper.TrackFX_SetParam(tr,helper_idx,2,i-1) --set Note# to i
pitches[#pitches+1],_,_=reaper.TrackFX_GetParam(tr, helper_idx, 3)
end
local notes=getNotes(tk,pitches,pp_qn,check_start,l_start)
if #notes>0 then
DBG("Start "..action.." notes...")
reaper.Undo_BeginBlock() -- create undo point for these notes
--always go backwards deleting notes
for i=#notes,1,-1 do
if action == edit_types.SELECT then
reaper.MIDI_SetNote(tk, notes[i].idx, true, nil, nil, nil, nil, nil, nil, nil)
else
reaper.MIDI_DeleteNote(tk,notes[i].idx)
end
end
reaper.Undo_EndBlock("DM "..action.." - ".. action.. " notes",4)
end
reaper.UpdateArrange()
end
reaper.defer(dMedit)
end
function getMidiEditorTrackTake()
local ame=reaper.MIDIEditor_GetActive()
local mode=reaper.MIDIEditor_GetMode(ame)
if mode > -1 then -- we are in a MIDI editor, -1 if ME not focused
tk=reaper.MIDIEditor_GetTake(ame)
--check that it's an actual take (in case of empty MIDI editor)
if not reaper.ValidatePtr(tk, 'MediaItem_Take*') then return nil,nil end
tr=reaper.GetMediaItemTake_Track(tk)
else
return nil,nil
end
return tr,tk
end
function prep()
DBG("in prep")
reaper.get_action_context() -- to clear is_new_value for checking
-- for new presses in main loop
tr,tk=getMidiEditorTrackTake()
if tk==nil then
if reaper.CountSelectedTracks()>0 then
tr=reaper.GetSelectedTrack(0,0)
local _,t_name=reaper.GetSetMediaTrackInfo_String(tr,"P_NAME"," ",false)
local _, ts=reaper.GetTrackState(tr)
if ts&64==64 and ts&2==2 then -- is rec armed and selected
local num_items=reaper.CountTrackMediaItems(tr)
if num_items>0 then
local l_start,l_end=reaper.GetSet_LoopTimeRange(false,true,0,0,true)
local cur=reaper.GetCursorPosition()
local i=1
while i<=num_items do
local it=reaper.GetTrackMediaItem(tr,i-1)
local i_start=reaper.GetMediaItemInfo_Value(it,"D_POSITION")
if math.floor(l_start*10)==math.floor(i_start*10) then
tk=reaper.GetActiveTake(it)
i=num_items
end
i=i+1
end
end
end
end
end
if tk~=nil and reaper.BR_IsTakeMidi(tk) then
helper_idx=getOrAddInputFx(tr,jsfx,true)
DBG("helper_idx="..helper_idx)
if helper_idx>-1 then
reaper.TrackCtl_SetToolTip("!-!-!-!-!-! Live "..action.." ACTIVE !-!-!-!-!-!", 800,20, true)
dMedit()
else
DBG("No effect added")
end
end
end
function cleanUp()
if helper_idx~=nil then
reaper.TrackCtl_SetToolTip("--- Live "..action.." Inactive ---", 800,20, true)
DBG("exit")
--removeJSEffect(tr,jsfx) --set chunk causes glitches
--so can't remove input FX
reaper.TrackFX_SetEnabled(tr, helper_idx, false) --just disable it
end
end
jsfx.body=[[
desc:Script Note Getter
slider1:0<0,1,1{On,Off}>Active (eats notes)
slider2:0<0,127,1>Notes in buffer
slider3:0<0,1000,1>Note # (for script)
slider4:0<0,127,1>Output Pitch
slider5:0<0,1,1>Trigger
@init
notebuf=0; //start pos of buffer
nb_width=3; //number of entries per note
buflen=0; //notes in buffer
function addRemoveNoteFromBuffer(m1,m2,m3)
(
s = m1&$xF0;
c = m1&$xF; // channel
n = m2;
v = m3; // velocity
init_buflen=buflen;
i = -1;
while // look for this note|channel already in the buffer
(
i = i+1;
i < buflen && (notebuf[nb_width*i]|0 != n || notebuf[nb_width*i+1]|0 != c);
);
(s == $x90 && v > 0) ? // note-on, add to buffer
(
notebuf[nb_width*i] = n;
notebuf[nb_width*i+1] = c;
notebuf[nb_width*i+2] = v;
i == buflen ? buflen = buflen+1;
)
: // note-off, remove from buffer
(
is_note_off=1;
i < buflen ?
(
memcpy(notebuf+nb_width*i, notebuf+nb_width*(i+1),
nb_width*(buflen-i-1)); // delete the entry
buflen = buflen-1;
);
);
buflen==init_buflen ? -1; //return value for nothing added/removed
);
@slider
p=slider3*nb_width; //position in buffer
slider4=notebuf[p];
@block
while (midirecv(offset,msg1,msg2,msg3))
(
slider1 ? (
midisend(offset,msg1,msg2,msg3);
):( //eating notes
msg1|$x90==$x90 ? (
addRemoveNoteFromBuffer(msg1,msg2,msg3);
);
msg1|$x80==$x80 ? (
addRemoveNoteFromBuffer(msg1,msg2,msg3)==-1 ? (
//no note in buffer, so allow trailing note-offs through
midisend(offset,msg1,msg2,msg3);
);
);
slider2=buflen;
);
)
]]
script_init=true
reaper.atexit(cleanUp)
script_init=false
reaper.Undo_BeginBlock()
prep()
reaper.Undo_EndBlock("DM Delete",-1)
|
|
|
08-13-2016, 05:21 PM
|
#29
|
Human being with feelings
Join Date: Aug 2015
Posts: 3,671
|
heh i had modified it from a two state button (127,0) to a repeated button (127 on, 127 off)
will test tomorrow, thanks again
|
|
|
08-14-2016, 08:21 AM
|
#30
|
Banned
Join Date: Sep 2015
Posts: 1,650
|
No probs btw it looks like learning with a note using helgoboss's ReaLearn means you can get the toggle off with note off now which isn't possible with native learn.
|
|
|
08-14-2016, 10:05 AM
|
#31
|
Human being with feelings
Join Date: Aug 2015
Posts: 3,671
|
ok, that latest one is working great with 127 on, 0 off.
new bug that i've noticed -- the last note in the item/time selection is not deleted sometimes. possibly having to do with if the note has a noteoff after or at the time selection loop point / midi item end.
also, perhaps most importantly, this script only seems to work on notes recorded in channel 1. anything recorded to other channels is not "caught" by the js input fx, i assume. i have 8 tracks set to record channels 1-8 respectively, and this script only works on track/channel 1.
i confirmed this with a multichannel midi track. i switched between channels 1-8 while recording midi notes into an item, and then attempted to DM delete them by channel. only channel 1 worked.
|
|
|
08-14-2016, 01:33 PM
|
#32
|
Banned
Join Date: Sep 2015
Posts: 1,650
|
Quote:
Originally Posted by mccrabney
ok, that latest one is working great with 127 on, 0 off.
new bug that i've noticed -- the last note in the item/time selection is not deleted sometimes. possibly having to do with if the note has a noteoff after or at the time selection loop point / midi item end.
|
That might be the look_ahead setting (formerly delete_ahead)...
Code:
local look_ahead=0.17 --so that notes don't sound
... try changing that to a higher value. The script is triggered X times a second whilst the project is playing so this looks ahead for an amount that should compensate for this.
Quote:
also, perhaps most importantly, this script only seems to work on notes recorded in channel 1. anything recorded to other channels is not "caught" by the js input fx, i assume. i have 8 tracks set to record channels 1-8 respectively, and this script only works on track/channel 1.
i confirmed this with a multichannel midi track. i switched between channels 1-8 while recording midi notes into an item, and then attempted to DM delete them by channel. only channel 1 worked.
|
Yes, it was single channel only. This version should be multi-channel. You need to delete the Script Note Getter script from your Reaper JS Effects folder so that it saves and loads the new version from the script first. Maybe make sure the any track doesn't have the old version of the Script Note Getter too.
In next post, it makes this one too long...
|
|
|
08-14-2016, 01:33 PM
|
#33
|
Banned
Join Date: Sep 2015
Posts: 1,650
|
Code:
-- D(rum) M(achine) Edit
-- run script and held notes will be edited in
-- either the active item in the MIDI editor or
-- on an item between the loop cursors of a the
-- first selected track, which must be rec-armed.
-- run script again to get out of edit mode
-- edit modes are: delete
-- or select
local function DBG(str)
--reaper.ShowConsoleMsg(str.."\n")
end
local edit_types={DELETE="Delete", SELECT="Select"}
local action = edit_types.DELETE;
jsfx={} --store details of helper effect
jsfx.name="Script Note Getter"
jsfx.fn="Script Note Getter"
--jsfx.body at end of script
function createJSEffect(fn,str)
local file=io.open(reaper.GetResourcePath().."/Effects/"..fn, "w")
file:write(str)
file:close()
end
function deleteJSEffect(fx)
os.remove(reaper.GetResourcePath().."/Effects/"..fx.fn)
end
--fx is table with .name and .fn (for filename)
function removeJSEffect(track,fx)
local chunk,ok="",false
ok,chunk=reaper.GetTrackStateChunk(track,chunk, false)
local pattern="(BYPASS %d %d %d[%c%s].JS \""..fx.name..".-WAK %d)"
local replacements
chunk,replacements=string.gsub(chunk,pattern,"")
if replacements>0 then
ok=reaper.SetTrackStateChunk(tr,chunk,false)
deleteJSEffect(fx)
return true
end
return false
end
function getOrAddInputFx(track,fx,create_new)
local idx=reaper.TrackFX_AddByName(track,fx.name,true,1)
if idx==-1 or idx==nil then
idx=reaper.TrackFX_AddByName(track,fx.fn,true,1)
if (idx==nil or idx==-1) and create_new==true then
createJSEffect(fx.fn,fx.body)
idx=getOrAddInputFx(track,fx,false)
return idx
else
tr=nil
return -1
end
end
idx=idx|0x1000000
reaper.TrackFX_SetEnabled(track, idx, true)
return idx
end
local look_ahead=0.17 --so that notes don't sound
function getNotes(tk,pitches,pp_qn,check_start,l_start)
local ni, tr, it
local midi={}
cnt=0
local ok, sel, mute, startpos, endpos, chan, pitch, vel=reaper.MIDI_GetNote(tk, 0)
while ok do
for i=1,#pitches,1 do
if pitch==pitches[i].note and chan==pitches[i].chan then
startpos=reaper.MIDI_GetProjQNFromPPQPos(tk, startpos)
endpos=reaper.MIDI_GetProjQNFromPPQPos(tk, endpos)
if (startpos<=pp_qn+look_ahead and endpos>=pp_qn) or
(check_start and startpos>=l_start and startpos<=l_start+look_ahead) then
local note={ type="note", idx=cnt, -- 6
select=sel,mute=mute, ostartpos=startpos, --12
startpos=startpos, endpos=endpos, len=endpos-startpos,
pitch=pitch, chan=chan, vel=vel }
midi[#midi+1]=note
end
end
end
cnt=cnt+1
ok, sel, mute, startpos, endpos, chan, pitch, vel=reaper.MIDI_GetNote(tk, cnt)
end
return midi
end
function dMedit()
local is_new_value,_,_,_,_,_,val=reaper.get_action_context()
if is_new_value then return end
-- tr, tk, helper_idx set in prep()
-- get number of held notes from helper plugin
nib=reaper.TrackFX_GetParam(tr, helper_idx, 1) --1=note in buffer
if nib>0 then
-- get loop points and check whether cursor is near the end
-- so we can delete on return to start of loop without them
-- playing
local l_start, l_end=reaper.GetSet_LoopTimeRange(false, false, 0, 0, false)
l_start=reaper.TimeMap2_timeToQN(0, l_start)
l_end=reaper.TimeMap2_timeToQN(0, l_end)
local pp=reaper.GetPlayPosition()
local pp_qn=reaper.TimeMap2_timeToQN(0, pp)
local check_start=l_end-pp_qn<look_ahead and true or false
--get held notes from buffer in helper plugin
local pitches={}
for i=1,nib,1 do
reaper.TrackFX_SetParam(tr,helper_idx,2,i-1) --set Note# to i
pitches[#pitches+1] = {}
pitches[#pitches].note,_,_=reaper.TrackFX_GetParam(tr, helper_idx, 3)
pitches[#pitches].chan = reaper.TrackFX_GetParam(tr, helper_idx, 4)
end
local notes=getNotes(tk,pitches,pp_qn,check_start,l_start)
if #notes>0 then
DBG("Start "..action.." notes...")
reaper.Undo_BeginBlock() -- create undo point for these notes
--always go backwards deleting notes
for i=#notes,1,-1 do
if action == edit_types.SELECT then
reaper.MIDI_SetNote(tk, notes[i].idx, true, nil, nil, nil, nil, nil, nil, nil)
else
reaper.MIDI_DeleteNote(tk,notes[i].idx)
end
end
reaper.Undo_EndBlock("DM "..action.." - ".. action.. " notes",4)
end
reaper.UpdateArrange()
end
reaper.defer(dMedit)
end
function getMidiEditorTrackTake()
local ame=reaper.MIDIEditor_GetActive()
local mode=reaper.MIDIEditor_GetMode(ame)
if mode > -1 then -- we are in a MIDI editor, -1 if ME not focused
tk=reaper.MIDIEditor_GetTake(ame)
--check that it's an actual take (in case of empty MIDI editor)
if not reaper.ValidatePtr(tk, 'MediaItem_Take*') then return nil,nil end
tr=reaper.GetMediaItemTake_Track(tk)
else
return nil,nil
end
return tr,tk
end
function prep()
DBG("in prep")
reaper.get_action_context() -- to clear is_new_value for checking
-- for new presses in main loop
tr,tk=getMidiEditorTrackTake()
if tk==nil then
if reaper.CountSelectedTracks()>0 then
tr=reaper.GetSelectedTrack(0,0)
local _,t_name=reaper.GetSetMediaTrackInfo_String(tr,"P_NAME"," ",false)
local _, ts=reaper.GetTrackState(tr)
if ts&64==64 and ts&2==2 then -- is rec armed and selected
local num_items=reaper.CountTrackMediaItems(tr)
if num_items>0 then
local l_start,l_end=reaper.GetSet_LoopTimeRange(false,true,0,0,true)
local cur=reaper.GetCursorPosition()
local i=1
while i<=num_items do
local it=reaper.GetTrackMediaItem(tr,i-1)
local i_start=reaper.GetMediaItemInfo_Value(it,"D_POSITION")
if math.floor(l_start*10)==math.floor(i_start*10) then
tk=reaper.GetActiveTake(it)
i=num_items
end
i=i+1
end
end
end
end
end
if tk~=nil and reaper.BR_IsTakeMidi(tk) then
helper_idx=getOrAddInputFx(tr,jsfx,true)
DBG("helper_idx="..helper_idx)
if helper_idx>-1 then
reaper.TrackCtl_SetToolTip("!-!-!-!-!-! Live "..action.." ACTIVE !-!-!-!-!-!", 800,20, true)
dMedit()
else
DBG("No effect added")
end
end
end
function cleanUp()
if helper_idx~=nil then
reaper.TrackCtl_SetToolTip("--- Live "..action.." Inactive ---", 800,20, true)
DBG("exit")
--removeJSEffect(tr,jsfx) --set chunk causes glitches
--so can't remove input FX
reaper.TrackFX_SetEnabled(tr, helper_idx, false) --just disable it
end
end
jsfx.body=[[
desc:Script Note Getter
slider1:0<0,1,1{On,Off}>Active (eats notes)
slider2:0<0,127,1>Notes in buffer
slider3:0<0,1000,1>Note # (for script)
slider4:0<0,127,1>Output Pitch
slider5:0<0,15,1>Output channel
slider6:0<0,1,1>Trigger
@init
notebuf=0; //start pos of buffer
nb_width=3; //number of entries per note
buflen=0; //notes in buffer
function addRemoveNoteFromBuffer(m1,m2,m3)
(
s = m1&$xF0;
c = m1&$xF; // channel
n = m2;
v = m3; // velocity
init_buflen=buflen;
i = -1;
while // look for this note|channel already in the buffer
(
i = i+1;
i < buflen && (notebuf[nb_width*i]|0 != n || notebuf[nb_width*i+1]|0 != c);
);
(s == $x90 && v > 0) ? // note-on, add to buffer
(
notebuf[nb_width*i] = n;
notebuf[nb_width*i+1] = c;
notebuf[nb_width*i+2] = v;
i == buflen ? buflen = buflen+1;
)
: // note-off, remove from buffer
(
is_note_off=1;
i < buflen ?
(
memcpy(notebuf+nb_width*i, notebuf+nb_width*(i+1),
nb_width*(buflen-i-1)); // delete the entry
buflen = buflen-1;
);
);
buflen==init_buflen ? -1; //return value for nothing added/removed
);
@slider
p=slider3*nb_width; //position in buffer
slider4=notebuf[p]; // note
slider5=notebuf[p+1]; // channel
@block
while (midirecv(offset,msg1,msg2,msg3))
(
slider1 ? (
midisend(offset,msg1,msg2,msg3);
):( //eating notes
msg1&$xF0==$x90 ? (
addRemoveNoteFromBuffer(msg1,msg2,msg3);
);
msg1&$xF0==$x80 ? (
addRemoveNoteFromBuffer(msg1,msg2,msg3)==-1 ? (
//no note in buffer, so allow trailing note-offs through
midisend(offset,msg1,msg2,msg3);
);
);
slider2=buflen;
);
)
]]
script_init=true
reaper.atexit(cleanUp)
script_init=false
reaper.Undo_BeginBlock()
prep()
reaper.Undo_EndBlock("DM Edit",-1)
Last edited by snooks; 08-14-2016 at 02:55 PM.
Reason: forgot to change one delete_ahead to look_ahead
|
|
|
08-14-2016, 03:27 PM
|
#34
|
Human being with feelings
Join Date: Aug 2015
Posts: 3,671
|
multichannel works great, thanks!
Quote:
Originally Posted by snooks
That might be the look_ahead setting (formerly delete_ahead)...
Code:
local look_ahead=0.17 --so that notes don't sound
... try changing that to a higher value. The script is triggered X times a second whilst the project is playing so this looks ahead for an amount that should compensate for this.
|
cool, tested this a bunch. tried .17, .5, 1, 5, and 10. i saw the same behavior displayed below in this screencap:
http://imgur.com/a/79dBj
(i have no idea why imgur won't let me embed this)
note that this only applies on notes that end or pass the end of the midi item. moving the end of the note into the range of dmdelete allows the script to act on it.
|
|
|
08-15-2016, 04:50 AM
|
#35
|
Banned
Join Date: Sep 2015
Posts: 1,650
|
Hmm, this is a tricky one... the notes extending beyond the boundary have an end position before the start position. Although the end position is at a PPQ position of zero - the start of the item - when checking for this, deleting any other note also deletes this note.
Here's a test script that outputs the contents of the MIDI item so you can see yourself...
Code:
local function DBG(str)
reaper.ShowConsoleMsg(str.."\n")
end
function outputMidi(tk)
local idx=0
local ok, sel, mute, startpos, endpos, chan, pitch, vel=reaper.MIDI_GetNote(tk, 0)
while ok do
DBG("idx: "..idx.." startpos: "..startpos.." endpos: "..endpos)
idx=idx+1
ok, sel, mute, startpos, endpos, chan, pitch, vel=reaper.MIDI_GetNote(tk, idx)
end
end
function getMidiEditorTrackTake()
local ame=reaper.MIDIEditor_GetActive()
local mode=reaper.MIDIEditor_GetMode(ame)
if mode > -1 then -- we are in a MIDI editor, -1 if ME not focused
tk=reaper.MIDIEditor_GetTake(ame)
--check that it's an actual take (in case of empty MIDI editor)
if not reaper.ValidatePtr(tk, 'MediaItem_Take*') then return nil,nil end
tr=reaper.GetMediaItemTake_Track(tk)
else
return nil,nil
end
return tr,tk
end
function start()
tr,tk=getMidiEditorTrackTake()
if tk==nil then
if reaper.CountSelectedTracks()>0 then
tr=reaper.GetSelectedTrack(0,0)
was_recording = reaper.GetPlayState(0)&4 == 4 and true or false
if was_recording then reaper.Main_OnCommand(1013, -1) end
local _,t_name=reaper.GetSetMediaTrackInfo_String(tr,"P_NAME"," ",false)
local _, ts=reaper.GetTrackState(tr)
if ts&64==64 and ts&2==2 then -- is rec armed and selected
local num_items=reaper.CountTrackMediaItems(tr)
if num_items>0 then
local l_start,l_end=reaper.GetSet_LoopTimeRange(false,true,0,0,true)
local cur=reaper.GetCursorPosition()
local i=1
while i<=num_items do
local it=reaper.GetTrackMediaItem(tr,i-1)
local i_start=reaper.GetMediaItemInfo_Value(it,"D_POSITION")
if math.floor(l_start*10)==math.floor(i_start*10) then
tk=reaper.GetActiveTake(it)
i=num_items
end
i=i+1
end
end
end
end
end
if tk~=nil and reaper.BR_IsTakeMidi(tk) then
DBG("\n\nMIDI Contents\n-------------")
outputMidi(tk)
end
end
start()
The only thing that sets the end position of the note correctly is touching the note in the MIDI editor, you don't need to move it. Trying to 'touch' the note via a script doesn't work, it deletes the notes.
Calling MIDI_Sort also deletes the notes, maybe because it does that with invalid notes. Unless there's anything anyone can think about I think the solution lies with the devs perhaps making MIDI_Sort check for end positions of 0 PPQ for notes that start after that time and doing whatever the MIDI editor does when you touch one of the notes.
|
|
|
08-15-2016, 07:21 AM
|
#36
|
Human being with feelings
Join Date: Aug 2015
Posts: 3,671
|
yeesh that's no fun.... one of those blurred lines between BR and FR. were i to make a thread addressed to the devs, describing and linking to this issue, where would you suggest posting?
issues like this is why i find myself often gluing track midi items to 1 per track
as a clumsy workaround, i wonder what'd happen if the script could check for such anomaly notes, and if yes, could add x amount of empty space to the midi item after the note? would that help, or would it just add duration to the note til the noteoff reached item end again?
when I've done this manually, i feel that I've seen both behaviors so I'm unclear as to what would happen
|
|
|
08-15-2016, 12:18 PM
|
#37
|
Banned
Join Date: Sep 2015
Posts: 1,650
|
I suppose a general bug here is that when notes like these exist, extending the unlooped item extends the note indefinitely. That's definitely not what was recorded, so it's defo a bug. Scripts not being able to do anything with these notes is just another symptom of the issue.
I think not recording the notes at the beginning of the loop and leaving the ends of the notes beyond the item boundary would be the way forward too.
I don't think extending the item via a script would result in consistently different behaviour from doing it via GUI. I'd give it a bash if I was fairly confident that it would, but I don't think it's worth trying.
|
|
|
08-16-2016, 08:19 AM
|
#38
|
Human being with feelings
Join Date: Aug 2015
Posts: 3,671
|
excellent. I'll try to file the BR and will link you to it here so you can add any details i omitted. meanwhile i think I'm gonna do the thing i didn't want to do and start creating project long midi items per midi track and editing everything using arrange synced midi items.
i do a lot of midi editing by slicing and copying midi items from arrange view so this means a lot of regluing all items on track for me, but whatever works (edit, didn't work, deleting "held-over" notes in the beginning deletes noteoff for "end-of-loop" notes, creating infinitely long notes.
edit, ugh this noteoff/loopend behavior is terrible...
Last edited by mccrabney; 08-16-2016 at 09:28 AM.
|
|
|
08-16-2016, 04:23 PM
|
#39
|
Banned
Join Date: Sep 2015
Posts: 1,650
|
Yeah, it could do with being fixed. It would be good if we could get some way to remove Input FX natively too, which would complete the picture with using temporary JSFX with scripts.
|
|
|
08-16-2016, 06:38 PM
|
#40
|
Human being with feelings
Join Date: Aug 2015
Posts: 3,671
|
will test tomorrow to see how this effects the "Select" function. if that works OK, one could just follow it up with a "delete" action once desired notes are selected.
|
|
|
Thread Tools |
|
Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -7. The time now is 07:57 AM.
|