外部プログラムの利用

 BASICの言語仕様の範囲では実行できない仕事が,外部プログラムを利用することで実行可能となることがあります。

 

 1. BASICプログラムを書き出して実行する

 Full BASICは,プログラムは実行開始時点で翻訳が終了していることが前提となっているので,実行中のプログラムが自分自身を書き換えて実行することは不可能です。
(仮称)十進BASICでは,プログラムをファイルとして書き出し,CHAIN文やEXECUTE文で実行することで,この束縛から逃れることができます。


関数f(x)をBASICの文法で入力すると,そのグラフを描く。(ver 5.4.0以降で実行してください)

100 REM xの数式を入力すると,-8≦x≦8の範囲でグラフを描く
110 DATA "SET POINT STYLE 1"
120 DATA "SET WINDOW -8,8,-8,8"
130 DATA "DRAW GRID"
140 DATA "FOR x=-8 TO 8 STEP 0.0004"
150 DATA "   WHEN EXCEPTION IN"
160 DATA "      PLOT POINTS:x,f(x)"
170 DATA "   USE"
180 DATA "   END WHEN"
190 DATA "NEXT x"
200 DATA "FILE DELETE ""temp.bas"""       ! 後始末
210 DATA "END"
220 INPUT PROMPT "f(x)=":s$          ! 関数の式を入力
230 OPEN #1:NAME "temp.bas"          ! BASICプログラムを書き出す
240 ERASE #1
250 PRINT #1:"DEF f(x)=";s$
260 DO
270    READ IF MISSING THEN EXIT DO: s$
280    PRINT #1:s$
290 LOOP
300 CLOSE #1
310 CHAIN "temp.bas"               ! 書き出したプログラムを実行 
320 END

temp.bas削除がtemp.bas自身の仕事になっているので,temp.basに文法誤りがあって実行できないとtemp.basファイルが残ってしまいます。そのため,文法誤りが出たときは,文法誤りがなくなるまで実行する必要があります。
それが問題になる場合は,CHAIN文の代わりにEXECUTE文を用い,EXECUTE文の次にFILE DELETEを書いてください。

100 REM xの数式を入力すると,-8≦x≦8の範囲でグラフを描く
110 DATA "SET POINT STYLE 1"
120 DATA "SET WINDOW -8,8,-8,8"
130 DATA "DRAW GRID"
140 DATA "FOR x=-8 TO 8 STEP 0.0004"
150 DATA "   WHEN EXCEPTION IN"
160 DATA "      PLOT POINTS:x,f(x)"
170 DATA "   USE"
180 DATA "   END WHEN"
190 DATA "NEXT x"
200 DATA "GSAVE ""TEMP.BMP"",""4bit""" ! 結果をファイルに保存して終了
210 DATA "END"
220 INPUT PROMPT "f(x)=":s$          ! 関数の式を入力
230 OPEN #1:NAME "temp.bas"          ! BASICプログラムを書き出す
240 ERASE #1
250 PRINT #1:"DEF f(x)=";s$
260 DO
270    READ IF MISSING THEN EXIT DO: s$
280    PRINT #1:s$
290 LOOP
300 CLOSE #1
310 EXECUTE "temp.bas"               ! 書き出したプログラムを実行 
320 FILE DELETE "temp.bas"           ! 後始末
330 WHEN EXCEPTION IN
340    GLOAD "TEMP.BMP"              ! 結果を受け取る
350    FILE DELETE "TEMP.BMP"        ! 後始末
360 USE
370 END WHEN
380 END


 実用的には,書き出すプログラムはDATA文にではなく,別のファイルに入れておく形にするのが合理的です。

2.他プログラムにデータを渡して処理してもらう

EXECUTE文は,EXEファイルを起動する目的にも使えます。そのEXEファイルの起動時パラメータは,EXECUTE文のWITH句で指定できます。


temp.txtを書き出してメモ帳で開く

10 DATA "Hello"
20 OPEN #1:NAME "A:temp.txt" 
30 ERASE #1
40 READ  s$
50 PRINT #1:s$
60 CLOSE #1
70 EXECUTE "NOTEPAD.EXE" WITH ("A:temp.txt")   
80 END



また,拡張子.txtをメモ帳に関連付けてあれば,70行を
70 EXECUTE "A:temp.txt"
としても,メモ帳が開きます。
 一般に,ファイル名を引数としてとることのできるプログラムであれば,この方法で処理を委ねることができます。
たとえば,(仮称)十進BASICではできないことが別のBASICではできるとしたら,そのBASICの文法で書かれたプログラムをファイルとして生成して,それを引数としてそのBASICをEXECUTE文で起動すればよいでしょう(そのBASICがそういうプログラムの引き渡し方を受け付けてくれればの話ですが)。
また,あて先と電文と納めたファイルのファイル名を引数として起動すればメールを送れるプログラムが存在すれば,BASICのプログラムでメールを送れることになります。

3.バイナリファイルを生成し,他プログラムに引き渡す

 プログラムのはじめに
OPTION CHARACTER BYTE
を書くと,“文字=バイト”になるので, nが0から255までの数値(整数)であるとき,
PRINT #1:chr$(n);
を実行すると,nがバイトとしてファイルに書き出されます。(文末にセミコロンが必要なことに注意)

つまり,ファイルのフォーマットが分かれば,任意のバイナリファイルが生成できることになります。
たとえば,音声ファイルのフォーマットが分かれば,それを合成し書き出して,play文で呼び出せば希望する音が出せることになります。一般に,処理を任せたいと考えるプログラムが,ファイル名を引数として起動するとそのファイルを読み込んで処理するようになっていれば,そのプログラムが要求するフォーマットでファイルを合成して書き出すことで,希望する処理が実行できます。また,実際に実行する人はいないと思いますが,EXEファイルのフォーマットが分かれば,EXEファイルを合成して,それをEXECUTE文で実行することも理論的には可能です。

なお,OPTION CHARACTER BYTE の有効範囲はプログラム単位です。外部副プログラムや外部関数定義を利用する場合には,主プログラムだけではなく,それらにも同様に書いておく必要があります。

WAVファイルを生成して演奏する

 WAVファイルフォーマットに関する情報は, WAV ファイルフォーマット があります。
十進BASIC掲示板に実際の作例が掲載されました。たかしさんからの情報ですが,実際の作者は別の方のようです。
なお,プログラムのはじめに
OPTION CHARACTER BYTE
を書いておけば,オプションメニューでの前操作は不要です。

REM testwave.bas 十進BASICによる音声ファイル生成プログラム 
REM (L:1KHz -10dB 正弦波、R: 振幅 -10dB {パワーは-11.76dB} 白色雑音)
REM chr$関数の引数として全ての1バイト整数が許される様に、オプションメニューの
REM 「互換性」「動作」で「文字列処理の単位」を「バイト」に設定して実行すること
LET d=10 !継続時間(秒)
LET f0=1000 !正弦波周波数(Hz)
LET db=-10 !生成波形の最大値(±32767を0dBとする)
LET fs=44100 !標本化周波数(Hz)
LET bps=fs*4 !1秒当りのデータ量(ステレオ16ビット量子化)
LET dsize=d*fs*4 !オーディオデータサイズ
LET fsize=dsize+36 !ファイルサイズ(先頭8Bを除く)
LET fmtsize=16 !フォーマットサイズ
LET channel=2^17+1 !ステレオPCMデータの指定
LET reso=2^20+4 !16ビットの指定
LET a=10^(db/20)
OPEN #6 : NAME "test.wav" !ファイルを開き、この名前のファイルが
ERASE #6 !既に存在していた場合には上書きを指定
LET t0=TIME
PRINT #6 : "RIFF"; !以下、wavファイルのヘッダーを作成
CALL out4(fsize) !
PRINT #6 : "WAVEfmt "; !
CALL out4(fmtsize) !
CALL out4(channel) !
CALL out4(fs) !
CALL out4(bps) !
CALL out4(reso) !
PRINT #6 : "data"; !
CALL out4(dsize) !ここまでがヘッダー用の出力
LET al=a*32767 !左チャネル係数
LET ar=a*65535 !右チャネル係数
LET k=f0/fs*PI*2 !引数の刻み
LET audio$="" !オーディオデータバッファを初期化
LET count=0 !カウンタをリセット
FOR i=1 TO d*fs
   LET lch=INT(SIN(i*k)*al+0.5) !左チャネルは1kHz正弦波
   IF lch<0 THEN LET lch=lch+65536 !負の数は補数表現
   LET rch=INT((RND-0.5)*ar+0.5) !右チャネルは白色雑音
   IF rch<0 THEN LET rch=rch+65536 !負の数は補数表現
   LET audio$=audio$&CHR$(MOD(lch,256))&CHR$(INT(lch/256))&CHR$(MOD(rch,256))&CHR$(INT(rch/256))
   LET count=count+1
   IF count=64 THEN !バッファデータが所定の長さ(64サンプル256Bがほぼ最適)に達したら
      PRINT #6 : audio$; !データをファイルに出力して
      LET audio$="" !バッファを初期化し
      LET count=0 !カウンタをリセット
   END IF 
NEXT i
PRINT #6 : audio$; !バッファに残ったデータを出力して
CLOSE #6 !ファイルを閉じる
PRINT "elapsed time = ";TIME-t0;"seconds"
SUB out4(i4) !4バイト整数の出力(little endian)
   LET j4=i4
   FOR m=0 TO 3
      PRINT #6 : CHR$(MOD(j4,256));
      LET j4=INT(j4/256)
   NEXT m
END SUB
END 


なお,Windows版十進BASICでは,この後,

PLAYSOUND "test.wav"
END

を実行すれば,音が聞けます。

4.一般的な注意

ファイル名を引数として指定して起動したとき,それをどう処理するかは,相手のEXEファイル次第です。


<参照>ver 5.4.0でのCHAIN文,EXECUTE文の動作の変更


戻る