Cakewalk Application Language(CAL)テクニック


このページでは、Cakewalk Music Software社(http://www.cakewalk.com)製のシーケンスソフトCakewalk Professionalシリーズのマクロ言語Cakewalk Application Language(CAL)のテクニックを紹介します。 最近流行の"CALS"とは関係ありませぬ。


CAL作成時の便利な機能

CAL作成中にファンクションのヘルプを見たいときは、Helpメニューを使わないで F1キーを使います。
調べたいファンクションにキャレット(カーソルと言った方がわかりやすいかも)を置きF1キーを押すと そのファンクションのヘルプが一発で開きます。 この方法は、操作をRecordボタンで記録し それを元にCALを作成する場合のパラメータ調べに特に便利です。


DLLを使ってみよう

DLLは、WindowsのOSの中のファンクションや、その他のプログラムの中のファンクションを呼び出すの機能です。 Windowsプログラムの資料がないと、どう使って良いかわからないので、幾つか使えそうなファンクションを挙げてみます。

*.iniファイルの読み書き

CALを終了しても値を保持したい場合など、DLLを使うと設定ファイル(*.ini)の読み書きをすることができます。 以下設定ファイル(skywater.ini)に書いて読んでみるサンプルCALです。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ini.cal
;; function:
;;   - read after write *.ini file
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 
;; By Satsuki Kojima 	GFC00217@nifty.ne.jp 
;; 6/18 1996

(do
  (int i)
  (getInt i "Input " 0 127)

  ; intの値をskywater.iniファイルに以下のように書き込みます。
  ; [Section]
  ; Entry=値

  (DLL "Kernel" "WritePrivateProfileString" "Section" "Entry" (format i) "skywater.ini")

  ; ちゃんと書けたか確認するために i をクリアします
  (= i 0)

  ; では、読んでみます。"0"はデフォルト値で、指定されたエントリが
  ; 見つからないときの値です。

  (= i (DLL "Kernel" "GetPrivateProfileInt" "Section" "Entry" 0 "skywater.ini"))
  (pause i) ;表示
)

こんなこともできる

フライングウインドウズのスクリーンセーバを起動します。 単なる冗談だってば。



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; joke.cal
;; function:
;;   - smile
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 
;; By Satsuki Kojima 	INET:GFC00217@nifty.ne.jp 
;; 10/28 1994

(do
	(DLL "Kernel" "WinExec" "ssflywin.scr /s" 1)
)



フェーダー風の入力方法

CALは、入力方法が少ないのが難ですね。 スクロールバーとかチェックボックス等を自由に作れたら入力の手間が省けると思うのですが,,,,,

そこで、"Y"キーを押している間は数値が連続して増え、"N"キーを押している間は数値が連続して減っていくような、フェーダーもどきのCALを作ってみました。 以下、SC-55のマスターボリュームをSysex制御する例です。 画面がチカチカしますが、頑張ればSysexエディタも作れるかも(^^;。

CALリファレンスにも載っているMessageBox関数をDLLコマンドで利用しています。 MessageBoxは、最後のパラメータを"35"にすると[Yes][No][Cancel]という3つのボタンを出すことができ、ボタンが押されると、それぞれ"6","7","2"が返ります。 これを利用して[Cancel]が押されるまでループしながら、"6"か"7"かで値を増減させています。 "Y"キーや"N"キーを矢印キーと思って押し続けることでフェーダー感覚で操作ができます。



; Master Volume Controler
; Roland SC-55 Master Volume format f0 41 10 42 12 40 00 04 xx sum f7
;
; By Kojima Satsuki gfc00217@nifty.ne.jp 6/8 1996

(do
  (int iVal 100) ; input value 
  (int iRet 0) ; return value of Message box
  (int iPartSum 68) ; sum of x40 x00 x04
  (int iSum 0) ; the check sum
  (if (< VERSION 31) (pause "require version >= 3.01"))
  
  (Play)

  (while (!= iRet 2) ; do until canceled
    (do 
      (message  "Master Volume " iVal) 
      
      ; ? YES/NO/CANCEL style MessageBox
      (= iRet (DLL "USER" "MessageBox" 0 
                (format "Increase ?  Yes:+  No:-  Cancel:Exit  " iVal) 
                "Master Volume" 35))
      (switch iRet
        6 (if (< iVal 127) (++ iVal)) ; Yes
        7 (if (> iVal 0) (-- iVal)) ; No 
      )
      (= iSum (% (- 128 (+ iPartSum iVal)) 128)) ; make checksum
      (sendMIDI 0 0 SYSX 65 16 66 18 64 00 04 iVal iSum)  
    )
  )
)


チェックボックス風の入力

Cakewalk Pro for Win 3.01からsendMIDIでシステムエクスクルーシブも送れます。 これを使ってMMCでレコードトラックを指定するCALを作ってみました。 Track 0..15 pRpp ppRp pppp ppppという風に入力ダイアログのメッセージを変数で変更しチェックボックス風に見せるところがミソです。


; Control MMC Record Ready (16 tracks)
;   sample of checkbox like dialog. 
;   by Kojima Satsuki GFC00217@nifty.ne.jp 5/26 1996
;
; MMC summery
; Record Ready:   F0 7F 7F 06 40 len1 4F len2 tb... F7
; len1 = 4F..tb(s)
; len2 = tb(s)
; tb... = track bitmap.
;
; this CAL send always 16 tracks bitmap
; len1 = const 05
; len2 = const 03

(do
	(include "need20.cal")
	(int iTr 0) ; toggle track
	
	;track bitmaps
	(int iByte1 0)
	(int iByte2 0)
	(int iByte3 0)
	(string szTr "Track 0..15 pppp pppp pppp pppp") ; 
	
	; track parameters -1 play 1 record ready
	(int iTr0 -1)
	(int iTr1 -1)
	(int iTr2 -1)
	(int iTr3 -1)
	(int iTr4 -1)
	(int iTr5 -1)
	(int iTr6 -1)
	(int iTr7 -1)
	(int iTr8 -1)
	(int iTr9 -1)
	(int iTr10 -1)
	(int iTr11 -1)
	(int iTr12 -1)
	(int iTr13 -1)
	(int iTr14 -1)
	(int iTr15 -1)
	
	(while (!= iTr -1)
		(do
			(getInt iTr szTr -1 15)
			(if (!= iTr -1)
				(do
					; Set the track parameter
					(switch iTr
						0 (*= iTr0 -1)
						1 (*= iTr1 -1)
						2 (*= iTr2 -1)
						3 (*= iTr3 -1)
						4 (*= iTr4 -1)
						5 (*= iTr5 -1)
						6 (*= iTr6 -1)
						7 (*= iTr7 -1)
						8 (*= iTr8 -1)
						9 (*= iTr9 -1)
						10 (*= iTr10 -1)
						11 (*= iTr11 -1)
						12 (*= iTr12 -1)
						13 (*= iTr13 -1)
						14 (*= iTr14 -1)
						15 (*= iTr15 -1)
					) ; switch iTr

					; create the track string
					(= szTr "Track 0..15  ")
					(if (<iTr0 0) 
						(="szTr" (format szTr "p")) 
						(="szTr" (format szTr "R")) 
					)
					(if (< iTr1 0) 
						(="szTr" (format szTr "p")) 
						(="szTr" (format szTr "R")) 
					) 
					(if (< iTr2 0) 
						(="szTr" (format szTr "p")) 
						(="szTr" (format szTr "R")) 
					) 
					(if (< iTr3 0) 
						(="szTr" (format szTr "p")) 
						(="szTr" (format szTr "R")) 
					) 
					(="szTr" (format szTr " ")) 
					(if (< iTr4 0) 
						(="szTr" (format szTr "p")) 
						(="szTr" (format szTr "R")) 
					) 
					(if (< iTr5 0) 
						(="szTr" (format szTr "p")) 
						(="szTr" (format szTr "R")) 
					) 
					(if (< iTr6 0) 
						(="szTr" (format szTr "p"))
						(="szTr" (format szTr "R")) 
					) 
					(if (< iTr7 0) 
						(="szTr" (format szTr "p")) 
						(="szTr" (format szTr "R")) 
					) 	
					(="szTr" (format szTr " ")) 
					(if (< iTr8 0) 
						(="szTr" (format szTr "p")) 
						(="szTr" (format szTr "R")) 
					) 
					(if (< iTr9 0) 	
						(="szTr" (format szTr "p")) 
						(="szTr" (format szTr "R")) 
					) 
					(if (< iTr10 0) 
						(="szTr" (format szTr "p")) 
						(="szTr" (format szTr "R")) 
					) 
					(if (< iTr11 0) 
						(="szTr" (format szTr "p")) 
						(="szTr" (format szTr "R")) 
					) 
					(="szTr" (format szTr " ")) 
					(if (< iTr12 0) 
						(="szTr" (format szTr "p")) 
						(="szTr" (format szTr "R")) 
					) (if (< iTr13 0) 
						(="szTr" (format szTr "p")) 
						(="szTr" (format szTr "R")) 
					) 
					(if (< iTr14 0) 
						(="szTr" (format szTr "p")) 
						(="szTr" (format szTr "R")) 
					) 
					(if (< iTr15 0) 
						(="szTr" (format szTr "p")) 
						(="szTr" (format szTr "R")) 
					) 
					; create track bitmaps 
					; bitmap1 
					(="iByte1" 0) 
					(if (> iTr0 0) 
						(+= iByte1 32)
					)
					(if (> iTr1 0) 
						(+= iByte1 64)
					)
					; bitmap2
					(= iByte2 0)
					(if (> iTr2 0) 
						(+= iByte2 1)
					)
					(if (> iTr3 0) 
						(+= iByte2 2)
					)
					(if (> iTr4 0) 
						(+= iByte2 4)
					)
					(if (> iTr5 0) 
						(+= iByte2 8)
					)
					(if (> iTr6 0) 
						(+= iByte2 16)
					)
					(if (> iTr7 0) 
						(+= iByte2 32)
					)
					(if (> iTr8 0) 
						(+= iByte2 64)
					)
					; bitmap3
					(= iByte3 0)
					(if (> iTr9 0) 
						(+= iByte3 1)
					)
					(if (> iTr10 0) 
						(+= iByte3 2)
					)
					(if (> iTr11 0) 
						(+= iByte3 4)
					)
					(if (> iTr12 0) 
						(+= iByte3 8)
					)
					(if (> iTr13 0) 
						(+= iByte3 16)
					)
					(if (> iTr14 0) 
						(+= iByte3 32)
					)
					(if (> iTr15 0) 
						(+= iByte3 64)
					)

					; send sysex
					(sendMIDI 0 0 SYSX 127 127 6 64 2 79 0) ; all safe  
					(sendMIDI 0 0 SYSX 127 127 6 64 5 79 3 iByte1 iByte2 iByte3)
					(message "SYSX " 127 127 6 64 5 79 3 iByte1 iByte2 iByte3)

					; for TRACK SYNC MONITOR	change 79 to 82
					; for TRACK INPUT MONITOR 	change 79 to 83
					; for TRACK MUTE		change 79 to 98
				)
			)
		)
	)
)

Editメニューの活用

初期バージョンでは、CALといえばforEachEventループを使ったプログラムしか作成できませんでしたが、最近のバージョンではメニューも利用できるようになりました。 メニューを併用すると、forEachEventでは難しかった操作も実現できます。 この例は、和音をその構成音の低い順に並べ替え、ギターのダウンストロークをシミュレートするものです。 高い音程から順に一音程ずつ別のトラックへ移動することにより、同時イベントの並べ替えを実現しています。



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; downpick.cal - down-picking simulator 
;; function:
;;   - sort the chord note. 
;;   - sepcho.cal will sort the each note of the chord by key.
;; use:
;;   - set the destination-track at the dialog.
;; note:
;;   - this cal cannot undo.
;;   - works better with the sepcho.cal.
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 
;; By Satsuki Kojima 	INET:GFC00217@nifty.ne.jp 
;; 10/28 1994

(do
	(include "need20.cal")	; Require version 2.0 or higher of CAL
	(pause "Use this CAL with single track mode!")
	(int nTrk 1)
	(getInt nTrk "destination track?" 1 256)
	(-- nTrk)	; CAL uses 0..255

	(int key)
	(= key 1)
	(while (!= key 129)
		(do
			(message "Moving NOTE : " (- key 1))
			
			(ResetFilter 0 1)
			(SetFilterRange 0 0 1 (- key 1) (- key 1))
			(SetFilterKind 0 KEYAFT 0)
			(SetFilterKind 0 CONTROL 0)
			(SetFilterKind 0 PATCH 0)
			(SetFilterKind 0 CHANAFT 0)
			(SetFilterKind 0 WHEEL 0)
			(SetFilterKind 0 SYSX 0)
			(SetFilterKind 0 TEXT 0)
			(SetFilterKind 0 LYRIC 0)
			(SetFilterKind 0 WAVE 0)
			(SetFilterKind 0 MCI 0)

			(EditCut From Thru 1 1 0 0 0 0)
			(EditPasteToTrack From 1 0 1 0 0 0 nTrk)
			
			(= key (+ key 1))
		)
	)

	(TrackActive 1 nTrk)
	(TrackName "DOWNPICK" nTrk)
)



リアルタイムメニューのコマンド

リアルタイムメニューの(Play),(Record),(Rewind)もCALコマンドとして使用することが可能です。 ちなみに、(Play),(Record)はトグルで、Play中に(Play)を実行すると演奏停止、 Record中に(Record)すると再生状態になります。
ここでは、(Play)コマンドを使った例を作ってみました。 曲の頭でWAVEファイルを再生するとき、WAVEファイルをMCIコマンドとしてを曲のシーケンスに入れてしまうと、WAVEファイルの長さが変わった時にWAVEファイルの長さに合わせてシーケンスをずらす必要があります。 このような場合にCALでWAVE再生終了後MIDIシーケンスを再生開始するように設定し、PLAYボタンではなくCALをRUNさせると、いちいち調整しないですみます。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; wavemidi.cal
;; function:
;;   - play midi after wave end
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 
;; By Satsuki Kojima 	GFC00217@nifty.ne.jp 
;; 6/22 1996
(do
	(DLL "MMSYSTEM" "sndPlaySound" "tada.wav" 0)
	(Play)
)

DDEによるCALの実行

Cakewalkは、DDEサーバー機能を持っていて、CALを別のアプリケーションからDDEを使って実行することもできます。 DDEと言ってもピンとこないでしょうから、DDEを使って制御しているアプリケーションを紹介します。 ダウンロードは、こちら


VIEWを再描画させるには

バッファファンクションの実行、つまりイベントを追加したり削除しただけでは、VIEWの表示は書き変わりません。 困ったもので、CALを実行し終わっても、CALの実行前の表示のままの場合があります。 これを避けるには、VIEWの書き換えが必要な時点で次のように何もしないforEachEventループを実行します。

	; Flash all views
	(forEachEvent NIL)

Copyright (C) 1996,2000 Kojima Satsuki (alias Sky & Water).