|
Post by olegaroyan on Jun 9, 2022 18:25:15 GMT
Hi! I really want to be able to record hi-hats changing in speed with my midi keyboard. I study programming at school so I decided that I kinda have to do it myself with the help of this great app Streambyter.
I want to achieve something like that :
I've read the manual but I can't even make simple note repeat properly.
if load assign L0 = 400 assign L1 = 500 end
#if note is C4 play it in a loop if M0 == 90 ^C3 +l send 80 M1 M2 +Dl0 send 90 M1 M2 +Dl1 math L0 = L0 + 400 math L1 = L1 + 400 # I put this here because the loop sends signals (judging by midi monitor like every millisecond
# but even with this home made wait() function it still sends hundreds of signals)
While T0 < 20000 end end end
# I want to stop the loop when I release C4 note if M0 == 80 ^C3 exit end
Can you please help ? this code makes infinitely repeat note .. Also do you think it will be possible to make this project in Streambyter? with all the synchronization with host AUM bpm?
|
|
|
Post by uncledave on Jun 10, 2022 10:47:35 GMT
Hi, You need to think of the body part of an SB script (outside the If Load block) as an Event Handler. One event (MIDI message) comes in, zero or more messages go out. The way to do what you want is to send an internal (+I) message, delayed (+D) to the time of the next beat. Handle that message by sending another note and another delayed message. You can calculate the delay time based on the SB tempo value. It's a little tricky; I might be able to show you some sample code. When the Note Off arrives from the controller, clear the repeat flag which you set when handling the Note On. And simply ignore the internal message that arrives after the flag is cleared.
To handle the possibility of really fast Note Ons from the controller, increment a (rotating) counter for each new note. Include the counter value in the internal message, and ignore internal messages with a counter value that is not current.
Cheers
|
|
|
Post by uncledave on Jun 10, 2022 17:00:48 GMT
Here's my suggested solution. You can set the number of ticks (24 per quarter note) between repeats. I put only 10 ms between note on and note off. What you need will depend on what the instrument expects. This version stops immediately when note off is received. (Note that you can put code between HTML code tags to keep it neat).
#NoteRepeat
If load
Alias $24 ppqn # number of ticks in a quarter note Alias ^C3 theNote # specific note to repeat Alias 80 maxCount # wrap around limit for counter
# this internal SysEx message uses the arbitrary index 17 define repeatEvent F0 7D 17
# local variables saved between events Alias J00 eventCount Alias J01 holdNote Alias J02 holdVelocity Alias J03 delayTime Alias J04 delayTicks Ass J00 = 0 0 0 0 0 0 0 0
# you could implement a CC or slider to adjust this Ass delayTicks = 6 # 6 ticks gives 16th notes
# returns the number of ms to delay for given number of ticks # SB BPM is beats in 100 min, 6000 sec, or 6000000 ms # BPM * ppqn is number of ticks in 100 min # dividing these gives ms per tick # multiply by number of ticks to delay gives delay in ms # division step is last for maximum precision. # using 32-bit P registers for these large numbers Sub ComputeDelay pResult pNumbTicks Mat P00 = $6000000 * pNumbTicks Mat P01 = ppqn * BPM Mat P02 = P01 / 2 Mat P00 = P00 + P02 # add half divisor for rounding Mat P00 = P00 / P01 Ass pResult = P00 End
# sends a note on/off pair now, and delayed internal SysEx for next time Sub SendNextNote Send 90 holdNote holdVelocity Send 80 holdNote 0 +D10 # vary this if necessary Send repeatEvent eventCount F7 +I +DdelayTime End
# initializes data for a new note input Sub ProcessNoteOn pNote pVel Ass holdNote = pNote # save note and velocity Ass holdVelocity = pVel ComputeDelay delayTime delayTicks # get delay time SendNextNote # send the first note End
End # Initialization ———————————————————————————
# The specific Note On and Note Off messages are blocked. # Any other MIDI passes right through.
If M0 == 90 theNote ProcessNoteOn M1 M2 Block End
# receiving the repeatEvent triggers the next note # stops if the count differs (because note off was received) # no need to block internal message If M0 == repeatEvent eventCount SendNextNote End
If M0 == 80 theNote # increment count and wrap around # wrap around prevents huge count value in case of long run Mat eventCount = eventCount + 1 Mat eventCount = eventCount % maxCount Block End Edit: Due to rounding, this will slide slightly forward or back with each repeat. If you're planning on holding for a long time, we can change it to be accurate to the millisecond. I left it out because it would clutter up the basic concept.
|
|
|
Post by mo13 on Jun 12, 2022 15:18:04 GMT
uncledave , would it be realistic to recreate something similair to this? patchstorage.com/flambae/With a bit of the same setup as the 'TickDelayLarge' script @having a clock fed to it. 6 sliders select drum voices, 1 master note-repeat and 1 sync on/off slider?
|
|
|
Post by olegaroyan on Jun 13, 2022 12:07:12 GMT
uncledave , thank you so much!!! I would never be able to write that in my lifetime I studied your suggested code and I almost completely understand it  ! I will try to make additions to it, but if I struggle, I'll post my further questions here
|
|
|
Post by uncledave on Jun 13, 2022 13:35:15 GMT
uncledave , thank you so much!!! I would never be able to write that in my lifetime I studied your suggested code and I almost completely understand it  ! I will try to make additions to it, but if I struggle, I'll post my further questions here Great! As I said, the trick is to focus on events. The MIDI stream is a sequence of events, and we can insert other events via internal messages. You can, of course, insert notes and CCs as well as SysEx. We chose SysEx because it effectively lets us "call" a subroutine after a delay. Sending the SysEx from the subroutine creates a loop over time. This trick is not mine; I learned it from the BlueVelvet factory preset. Edit: Please ask about anything not clear in my script. It should all be obvious, with a little help from the manual. But I realize that SB has some features that are unusual in modern programming langusges, and I'd be happy to clarify them. For instance, all subroutine parameters are passed by reference (in/out), so when the Sub modifies the parameter, it actually modifies the variable in the subroutine call. That's how ComputeDelay can return the delayTime. Edit 2: Just realized there's an error in my script. Near the top, maxCount should be Alias 80 maxCount
Because the count is sent in a MIDI message, the value cannot exceed 7F ($127). I'll edit the original post as well.
|
|
|
Post by mo13 on Dec 31, 2022 8:25:01 GMT
# you could implement a CC or slider to adjust this Ass delayTicks = 6 # 6 ticks gives 16th notes
Could anyone give me a hand on how to implement a slider in the Q array for this in the above uncledave 's script? i tried assigning different ticks to the K array say, 2, 4, 6, 8 etc followed by assigning delayTicks to QK0 but that's not working out exactly how it should.
|
|