Jump to content

CAL script, I need help, please


Hans Smedsrud

Recommended Posts

Dear experts

I have been struggling for a few days trying to write a CAL script. The script is supposed to double note duration and slide them to the right, so they don't all end up in a pile on top of each others. Because I am new to CAL/LISP, I don't know what it can do, or it's limitations.

I have written some PSEUDO code, to explain what I want the script to do, please have a look.

PSEUDO CODE

;REM Variables (Never mind the misspelling, it's like that to not conflict with CAL constants and such)
dword dOffsett=0

;REM Timing
dword nTime = 0 

;REM Current Track
integer ChanA = Event.Chan

;REM New track/chan
integer ChanB = 2 ;Default, may be altered by User input later

;REM Note key
integer NoteK = 60 ;Note C4

;REM Note length/ duration
integer NoteL = 0 

;REM counter
integer i = 1


FOR EACH EVENT IN SELECTED CHANNEL
  IF ((Event.Kind == NOTE) && (Note.Dur > 0)) 
   THEN [

      ;REM Save current data
      LET NoteK = Note.Key
      LET nTime = Event.Time
      LET NoteL = Note.Dur

     ECHO   " Currently processing: Event " i  " ->" (meas nTime) ":" (beat nTime) ":" (tick nTime) " 

      ;REM Manipulate the data (and save to new channel)
      LET nTime = (Event.Time + dOffsett)  ;REM Let us slide the new note by current offset
      LET dOffsett = (dOffsett + NoteL) ;REM Update the offset, who will affect the next NOTE
      LET NoteL = (NoteL * 2)  ;REM Double the note duration

      ;REM Save the new data to the new channel

      WRITE nTime ChanB NOTE NoteK Note.Vel NoteL

      ;REM Which According to CAL Reference guide, should be this:
      (insert nTime ChanB NOTE NoteK Note.Vel NoteL)
      ;REM BUT THE LINE ABOVE DOES NOT WORK, IT STORES THE "NEW" DATA IN THE SELECTED / ACTIVE CHANNEL, WHY?

      i++

    }
  ELSE { Do nothing! }
  END IF
NEXT

---
Please remember that this is PSEUDO code, and just a subjective mix of different languages. But I think that a CAL / LISP expert should be able to get the grasp of it.
I hope someone are able to help me solve this problem. 

Thanks in advance 🙂

Link to comment
Share on other sites

A couple of things Hans:

Do you have the CAL manual?

Are you intentionally trying to learn CAL?

I've written a few CAL routines, and with all my years of software development, I find it a fun challenge but not too often. If you have the CAL mostly written and want to post it, I can take a look at it. There are others on this forum that are more skilled at CAL than I am and could also probably help you.

Also, if I'm not misunderstanding your goal, you are trying to double the length of the midi sequence, i.e., double the note lengths and also double the note offsets so that you end up with the same sequence, but twice as long.

There is a built-in function, "Length", that does this, which you can access by selecting the midi, a selecting the "Length" function from the "Process" menu.

  • Like 1
Link to comment
Share on other sites

1 minute ago, billp said:

Also, if I'm not misunderstanding your goal, you are trying to double the length of the midi sequence, i.e., double the note lengths and also double the note offsets so that you end up with the same sequence, but twice as long.

There is a built-in function, "Length", that does this, which you can access by selecting the midi, a selecting the "Length" function from the "Process" menu.

That's the way I interpreted it as well. Process > Length at 200% should do the trick.

  • Like 1
Link to comment
Share on other sites

8 hours ago, billp said:

A couple of things Hans:

Do you have the CAL manual?

Are you intentionally trying to learn CAL?

I've written a few CAL routines, and with all my years of software development, I find it a fun challenge but not too often. If you have the CAL mostly written and want to post it, I can take a look at it. There are others on this forum that are more skilled at CAL than I am and could also probably help you.

Also, if I'm not misunderstanding your goal, you are trying to double the length of the midi sequence, i.e., double the note lengths and also double the note offsets so that you end up with the same sequence, but twice as long.

There is a built-in function, "Length", that does this, which you can access by selecting the midi, a selecting the "Length" function from the "Process" menu.

;REM "DOUBLE TROUBLE", a CAL script by Hans Smedsrud

(do
     (dword dOffsett 0) ;Offset, starts at 0
    (dword nTime 0) ;Timing
    (int ChanA Event.Chan);
    (int ChanB 2) ; New track
    (int NoteK 60) ;C4 Note KEY
    (int NoteL 0) ;Note length/duration
    (int i 0); Counter
)


(do
    (if (&& (== Event.Kind NOTE) (> Note.Dur 0))     
       (do
        ;REM Save current data
           (= NoteK Note.Key) 
        (= nTime Event.Time)
        (= NoteL Note.Dur) 

        ;REM Manipulate the data and save to new channel
        (= nTime (+ Event.Time dOffsett))
        (= dOffsett (+ dOffsett NoteL)) ;REM Update the offset, who will affect the next NOTE
        (= NoteL (* NoteL 2))  ;REM Double the note duration

        (message 
          " Currently processing: Event: "  i  " ->"  (meas nTime) ":" (beat nTime) ":" (tick nTime) "   ")

        (insert nTime  ChanB NOTE NoteK Note.Vel NoteL)

        (++ i)
        )
    NIL
    )
)

NIL
----

Thanks for reply. Well, manual? Got something written by Glen Cardenas, but probably not the official Cakewalk CAL script manual. And it would of course be nice to write a working CAL script and learn a new dialect/language in the process.

Any idea what's wrong with my script?

 

Link to comment
Share on other sites

So here's my take:

The "channel" reference is just that: it refers to the channel, not the track, that is assigned to the note. Each track can contain notes from channels for channels 1-16. Your new notes are being written to the same track, just a separate channel.

Read the section on implicit and explicit track references too. I think this is a problematic area for CAL.

In your case, since you coded "2" for the new channel, the notes will be generated for channel "3", since CAL channel references are zero-based, while CbB channel references are 1-based.

Your code works fine otherwise, at least on simple midi sequences. I separated the generated notes from the originals by using the Edit/Select by filter and selecting the notes on channel "3". I didn't try the script against overlapping notes. That's as far as I went tonight.

Caltest.mid

  • Like 1
Link to comment
Share on other sites

I use web translations, so this may not be what you are looking for.

Is the purpose simply to double the specified range?
If not from the menu process, but to be performed in CAL.

(do
    (EditLength From Thru 0 200 1 1)
)

This should double the selected target.


Note for CAL training only.
Although CAL processes the data within the specified range sequentially, there are many cases where the data is not processed in order of event time.
Therefore, CAL that simply uses the previously processed data may malfunction.
*Confirmed by experimentation with a self-made CAL.

CAL does not have an array, so there is no sort function. You must create your own arrays.

If the theme is to process continuous data in CAL, I think the difficulty level is quite high.

  • Like 1
Link to comment
Share on other sites

22 hours ago, billp said:

There is a built-in function, "Length", that does this, which you can access by selecting the midi, a selecting the "Length" function from the "Process" menu.

 

22 hours ago, David Baay said:

That's the way I interpreted it as well. Process > Length at 200% should do the trick.

 

Hi. Well, yes you guys are right, I wanted to double the MIDI note lenghts and slide them accordingly, to stretch out the MIDI part. The MIDI part is a Grieg piece I recorded a few years ago, but it's too fast for the audio I recorded recently. The Grieg piece is in the original 2/4 Time Signature, my audio is a Guitar Solo in 4/4 (Rock beat).
I know I could of course re-record the MIDI part, or change the note one by one in the Piano Roll, but I was looking for an easier solution. I did not know about the "Lenght" feature in Cakewalk, but it seem to work, when set to approx 200% (to fit my Audio). 
Funny, because I googled this subject a lot, before I attempted to write a CAL script. I did find lots of people wanting to do the same as me, but there were no solutions presented. Thank you both 🙂🙏

 

21 hours ago, sjoens said:

You can also Ctrl+Shift+Drag the end of a clip to stretch it to desired length in Track View.

You can also lasso select (right click & drag) notes in PRV and do the same.

Set Snap for precision.

Thanks. I knew about this solution, but I thought it was not precise enough, and that it's very easy to mess it up by dragging it too short or too far. Hence I wanted some exact way to do it, to align the MIDI track perfectly to the measure/beats.

13 hours ago, billp said:

So here's my take:

The "channel" reference is just that: it refers to the channel, not the track, that is assigned to the note. Each track can contain notes from channels for channels 1-16. Your new notes are being written to the same track, just a separate channel.

Read the section on implicit and explicit track references too. I think this is a problematic area for CAL.

In your case, since you coded "2" for the new channel, the notes will be generated for channel "3", since CAL channel references are zero-based, while CbB channel references are 1-based.

Your code works fine otherwise, at least on simple midi sequences. I separated the generated notes from the originals by using the Edit/Select by filter and selecting the notes on channel "3". I didn't try the script against overlapping notes. That's as far as I went tonight.

Caltest.mid 223 B · 0 downloads

Thanks. I have not tested your script yet. But I will do it soon 😀

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...