Jump to content

CAL script for removing same event type on same tick?


quattj

Recommended Posts

Does anyone have a CAL script for removing "duplicate" events that occur on the same tick, but contain different values?

I have a MIDI file I am trying to clean up that has hundreds of volume events that happen on the same ticks (same track, same channel), meaning there are hundreds of tick values that contain two or more volume events with differing values for the same notes.

So for example:

Tick 510 -> Note On

Tick 540 -> volume 64

Tick 540 -> volume 73

Theoretically the first event should get ignored because they both happen at the same time, but the values that are set in my file may need to keep the first OR the second, so I would hopefully be able to specify if I wanted to remove either all the first occurrences, all the second occurrences, etc.

Link to comment
Share on other sites

7 hours ago, quattj said:

Theoretically the first event should get ignored because they both happen at the same time, but the values that are set in my file may need to keep the first OR the second, so I would hopefully be able to specify if I wanted to remove either all the first occurrences, all the second occurrences, etc.

CbB will send all of the events in the order they appear in the Event list. Since MIDI is inherently a serial protocol, the order of events will be preserved in transmission even if the one-message-millisecond transmission rate of a physical MIDI port can't keep up with many events being sent on the same tick, and whichever one is received last by the synth will "win".

All the events in a clip have an array index so you could theoretically write an undupe script to delete the first, second, third, etc. instance of every "duplicate" event on a given timestamp. But it can't "know" in advance how may dupes it will encounter on a given timestamp until it's passed the last one (unless you know for certain that every event is duplicated the same number of times). So you would need to go through the loop once to find the index of the last dupe on each timestamp, one at a time, and then iterate through the sequence a second time to delete it. Then go through the sequence again, ignoring that first timestamp group to find the index of the next "last dupe", etc, etc.

I'm not aware of an existing CAL that's designed to do anything like this for controllers. I could write one, but I'm so rusty with CAL, it would be a long and painful process. ;^)

It would be significantly easier to write a CAL to just keep the first event it finds and delete all subsequent events of the same type on the same timestamp. That could be done in a single pass. And you could adapt the existing UNDUPE.CAL for note events to do it (or one of the revised ones that addresses a bug in the original). 

Link to comment
Share on other sites

I have created a CAL script that removes controller events that are of the same number AND that are are less than 15 ticks than the first of selected controller events.  It also removes controller events that are of the same controller number AND that are the same values.

(do
    (int resolution 15)
    (long Previous_test_time)
    (int Previous_CC_Value)
    (int can_delete 1)
    (long first_time)
    (long last_time)
    (int cc_index 1)
    ;find first CC Value and its time
    (forEachEvent
        (if (== Event.Kind CONTROL)
            (if (== cc_index 1)
                (do
                    (= first_time Event.Time)
                    (= Previous_CC_Value Control.Val)
                    (++ cc_index)
                ) (= last_time Event.Time))))
    
    ;thin out
    (= Previous_test_time first_time)
    (forEachEvent
        (do
            (= can_delete 1) ;assume can delete
            (if (|| (== Control.Val 0) (== Control.Val 127)) (= can_delete 0))
            (if (== Control.Val 63) (= can_delete 0))
          (if (|| (== Event.Time first_time) (== Event.Time last_time)) (= can_delete 0))
            (if (&& (== Event.Kind CONTROL) (== can_delete 1))
                (if (<= (- Event.Time Previous_test_time) resolution)
                    (do
                        (if (&& (!= Event.Time first_time) (!= Event.Time last_time))
                            (delete)
                        ); enf if
                    ); End do
                    (do
                        (= Previous_test_time Event.Time)
                    );end do
                );end IF
            ); end if
        );end do
    );end for
    (forEachEvent
        (do
            (= can_delete 1) ;assume can delete
          (if (|| (== Event.Time first_time) (== Event.Time last_time)) (= can_delete 0))        
            (if (&& (== Event.Kind CONTROL) (== can_delete 1))
                (if (== Control.Val Previous_CC_Value)
                    (do
                        (delete)
                    );end do
                    (do
                        (= Previous_CC_Value Control.Val)
                    );end do    
                );end if
             );end if
        );end do
    ); end for
);end do

Edited by Promidi
  • Like 1
Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...