; ------------------------------------------------------------------------------------------------- ; Split Track by Instruments.cal ; ------------------------------------------------------------------------------------------------- ; ; Author: Eric von Bayer ; Email: CAL @ ericvonbayer.us (remove the spaces) ; WWW: http://www.ericvonbayer.us ; Dates: Aug 2002 - October 2006 ; Version: 3.2 ; Description: ; ; A really cool script to seperate out tracks by patch change messages. Lots of patch changes ; will slow it down, though it's MUCH faster than the original. It can't handle the data before ; the first patch change due to limitations in Cakewalk. It'll leave that as a seperate track. ; It also can't determine the starting bank, so any patch changes that don't specify will be -1. ; Aside from that it should work adequately. It will also perserve Wheel, Mod, Volume, and ; Expression across splits now. ; ; ------------------------------------------------------------------------------------------------- ; Make Sure we're new enough ; ------------------------------------------------------------------------------------------------- (do (if (< VERSION 40) (do (pause "This CAL program requires CAL version 4.0 or higher") (exit) ) ) ; ------------------------------------------------------------------------------------------------- ; Config Section ; ------------------------------------------------------------------------------------------------- (int bKillPatchChanges FALSE) ; Should we kill patch changes? ; ------------------------------------------------------------------------------------------------- ; User Input ; ------------------------------------------------------------------------------------------------- ; NOTE: I wish Cakewalk cound report back what track was selected, but just use 1 (int nSrcTrk 1) (getInt nSrcTrk "Source Track?" 1 256) (-- nSrcTrk) ; CAL uses 0..255 ; NOTE: I wish Cakewalk would tell me how many tracks existed (int nDestTrk (+ nSrcTrk 2) ) (getInt nDestTrk "First Destination Track?" 1 256) (-- nDestTrk) ; CAL uses 0..255 ; If markers not set, select entire range (if (== From Thru) (do (= From 0) (= Thru End) ) ) ; ------------------------------------------------------------------------------------------------- ; Initialization ; ------------------------------------------------------------------------------------------------- ; Save from and thru (dword dFrom From) (dword dThru Thru) ; Set filter params. (ResetFilter 0 TRUE) ; "Constants" (int nTooBig 16385) (int nTooSmall -16385) (long lTooSmall -3000000) (long lTooBig 3000000) (dword NotResume -1) (dword dTimeMul (/ 960 TIMEBASE) ) ; Variables for tracking (int nCurBank nTooBig) ; Current bank we're operating on (int nCurPatch nTooBig) ; Current number we're operating on (long lCurBNP lTooBig) ; Current bank we're operating on (long lDoneBNP lTooSmall) ; Current bank we're operating on (dword dResStart dFrom) ; Resume position to continue (dword dCopyBeg 0) ; Start of copy selection (dword dCopyEnd 0) ; End of copy selection (int nBlockCount 1) ; Number of blocks moved to the current track (int nChanOff 0) ; Track offset (int bInBlock FALSE) ; Are we in a block we're going to copy? (int bHaveBlock FALSE) ; Do we have our block already? (long lBNP 0) ; variable for tracking bank and patch (int iWheel -1) ; Variable to hold last wheel position (int iMod -1) ; Controller to hold the last Mod position (int iVolume -1) ; Controller to hold the last Volume position (int iExpr -1) ; Controller to hold the last Expression position ; ------------------------------------------------------------------------------------------------- ; Copy any data that we don't know what patch it is ; ------------------------------------------------------------------------------------------------- ; NOTE: I wish I didn't have to do this, but since I can't read back the patch/bank from ; Cakewalk, I have to just chuck it in a seperate track and let the user deal with it ; Restore From and Thru/track (= Thru dThru) (= From dFrom) (TrackSelect 0 -1) (TrackSelect 1 nSrcTrk) ; Traverse all the events (int bFirstEventPatch TRUE) ; Is there previous data (forEachEvent (do ; Do we have a block yet (if (== bHaveBlock FALSE) (do ; Do we have a patch change? (if (== Event.Kind PATCH ) (do (= dCopyEnd Event.Time) (= bHaveBlock TRUE) ) ) ) ) ) ) (if (&& (== bHaveBlock TRUE) (== bFirstEventPatch FALSE) ) (do (EditCopy dFrom dCopyEnd TRUE FALSE FALSE FALSE FALSE) (EditPasteToTrack dFrom 1 1 TRUE FALSE FALSE FALSE (+ nDestTrk nChanOff) ) ; Setup The Track (TrackName (format "Split [??/??]" ) (+ nDestTrk nChanOff) ) (TrackBank nCurBank (+ nDestTrk nChanOff) ) (TrackPatch nCurPatch (+ nDestTrk nChanOff) ) ; Bump the offset (++ nChanOff) ) ) ; ------------------------------------------------------------------------------------------------- ; Main search/copy code ; ------------------------------------------------------------------------------------------------- ; NOTE: This process sucks pretty badly, but since there's no arrays or stacks, ; and I can't copy from within a forEachEvent, and I can't deselect events on ; an individual basis, and I can't insert events into any track except the ; selected one... This will just have to do. Pretty stupid to cover each event ; a few hundered times, but such is life. ; Go until we run out of instruments (while (> nBlockCount 0) (do ; Reset block status to get into while loop (= nBlockCount 0) (= dResStart dFrom) ; Reset the Bank/Patch (= nCurBank nTooBig) (= nCurPatch nTooBig) (= lCurBNP lTooBig) (while (!= dResStart NotResume) (do ; Restore From and Thru/track (= Thru dThru) (= From dResStart) (TrackSelect 0 -1) (TrackSelect 1 nSrcTrk) ; Reset the block status (= bInBlock FALSE) (= bHaveBlock FALSE) (= dResStart NotResume) (= iWheel -10000) (= iMod -1) (= iVolume -1) (= iExpr -1) ; Traverse all the events (forEachEvent (do ; Do we have a patch change? (if (== Event.Kind PATCH ) (do (= lBNP (+ (* 128 Patch.Bank ) Patch.Num ) ) ; If this is a lower patch but is above the already done ones (if (&& (< lBNP lCurBNP ) (> lBNP lDoneBNP) ) (do ; Prime the Number and Bank (= nCurPatch Patch.Num) (= nCurBank Patch.Bank) (= lCurBNP lBNP) ; Reset the block status (= bInBlock FALSE) (= bHaveBlock FALSE) ) ) ; Does this match us (if (== lBNP lCurBNP) (do ;Do we already have a stream open (if (== bInBlock FALSE) (do ;Start a new selection (= dCopyBeg Event.Time) (= bInBlock TRUE) ) ) ) (do ( if (&& (== bInBlock TRUE ) (== bHaveBlock FALSE) ) ( do; (= dCopyEnd (- Event.Time 1) ) (= bHaveBlock TRUE) (= dResStart Event.Time ) ) ) ) ) ) (do ; Else portion (type != PATCH) || (time < dResStart) ; If we don't yet have a block, capture controllers till we do (if (&& (== bHaveBlock 0) (== bInBlock 0) ) (do (if (== Event.Kind WHEEL ) (= iWheel Wheel.Val) ) (if (&& (== Event.Kind CONTROL ) (== Control.Num 1) ) (= iMod Control.Val) ) (if (&& (== Event.Kind CONTROL ) (== Control.Num 7) ) (= iVolume Control.Val) ) (if (&& (== Event.Kind CONTROL ) (== Control.Num 11) ) (= iExpr Control.Val) ) ) ) ) ) ; End of main if type == PATCH ) ) ; End of ForEachEvent ; End off any unterminated blocks (if (&& (== bInBlock TRUE) (== bHaveBlock FALSE) ) (do (= dCopyEnd Event.Time ) (= bHaveBlock TRUE) ) ) ; Do we already have a stream open (if (== bHaveBlock TRUE) (do ; End off the selection ;(= From dCopyBeg) ;(= Thru dCopyEnd) ; Handle Timebase correction (*= dCopyBeg dTimeMul) (*= dCopyEnd dTimeMul) ; Move it to the new track (EditCopy dCopyBeg dCopyEnd TRUE FALSE FALSE FALSE FALSE) (EditPasteToTrack dCopyBeg 1 1 TRUE FALSE FALSE FALSE (+ nDestTrk nChanOff) ) ; Insert the needed messages (TrackSelect 0 -1) (TrackSelect 1 (+ nDestTrk nChanOff) ) (if (!= iWheel -10000) (insert (- dCopyBeg 1) 0 WHEEL iWheel) ) (if (!= iMod -1) (insert (- dCopyBeg 1) 0 CONTROL 1 iMod) ) (if (!= iVolume -1) (insert (- dCopyBeg 1) 0 CONTROL 7 iVolume) ) (if (!= iExpr -1) (insert (- dCopyBeg 1) 0 CONTROL 11 iExpr) ) ; Flag that we moved data (++ nBlockCount) (message "Splitting [" nCurBank "/" nCurPatch "] to track " (+ nChanOff nDestTrk) "(" nBlockCount ") {" dCopyBeg "-" dCopyEnd "}" ) ) ) ) ) ; End of the while which covers all of ForEachEvent ; Setup the track details if we found a track (if (< lCurBNP lTooBig ) (do (pause "Done with " lCurBNP " [" nCurBank "/" nCurPatch "] -> Track " (+ nDestTrk nChanOff) ) ; Setup The Track (TrackName (format "Split [" nCurBank "/" nCurPatch "]" ) (+ nDestTrk nChanOff) ) (TrackBank nCurBank (+ nDestTrk nChanOff) ) (TrackPatch nCurPatch (+ nDestTrk nChanOff) ) ; Bump the offset (++ nChanOff) ; Mark this bank/patch done (= lDoneBNP lCurBNP) ) ) ) ) ; End of While ; Select all the split tracks patch data and kill it (if (== bKillPatchChanges TRUE ) (do (ResetFilter 0 FALSE) (TrackSelect 0 -1) (int nChanSel 0) (while (< nChanSel nChanOff) (do (TrackSelect 1 (+ nDestTrk nChanSel) ) (++ nChanSel) ) ) (SetFilterKind 0 PATCH TRUE) (EditDelete40 TRUE FALSE FALSE FALSE FALSE) ) ) ; Reset the filters and ranges (TrackSelect 0 -1) (ResetFilter 0 TRUE) (= From dFrom) (= Thru dThru) )