110 OPTION ARITHMETIC NATIVE 120 DECLARE EXTERNAL FUNCTION DWORD$, WORD$ 130 LET file$="BeatWave.WAV" 140 DEF wl(t)=SIN(2*PI*440*t) 150 DEF wr(t)=SIN(2*PI*441*t) 160 LET duration=5 ! 継続時間(秒) 170 LET fs=44100 ! 標本化周波数(Hz) 180 LET SIZE=duration*fs 190 OPEN #1: NAME file$ 200 ERASE #1 210 PRINT #1: "RIFF"; 220 PRINT #1: DWORD$(SIZE*2*2 + 36); 230 PRINT #1: "WAVE"; 240 PRINT #1: "fmt "; 250 PRINT #1: DWORD$(16); 260 PRINT #1: WORD$(1); ! リニアPCM 270 PRINT #1: WORD$(2); ! チャンネル数=2(ステレオ) 280 PRINT #1: DWORD$(fs); 290 PRINT #1: DWORD$(fs*2*2); ! データ速度(byte/sec) 300 PRINT #1: WORD$(2*2); ! ブロックサイズ 310 PRINT #1: WORD$(16); ! ビット数 320 PRINT #1: "data"; 330 PRINT #1: DWORD$(SIZE*2*2); ! 波形データバイト数 340 FOR i=0 TO SIZE-1 350 LET t=i/fs 360 PRINT #1: WORD$(ROUND(32767*wl(t))); 370 PRINT #1: WORD$(ROUND(32767*wr(t))); 380 NEXT i 390 CLOSE #1 400 PLAYSOUND file$ 410 END 1000 ! 外部関数定義 DWORD$ (32ビット整数化した文字列(4バイト)) 1010 EXTERNAL FUNCTION DWORD$(n) 1020 OPTION ARITHMETIC NATIVE 1030 OPTION CHARACTER byte 1040 LET r=MOD(n,2^8) 1050 LET s$=CHR$(r) 1060 LET n=(n-r)/2^8 1070 LET r=MOD(n,2^8) 1080 LET s$=s$ & CHR$(r) 1090 LET n=(n-r)/2^8 1100 LET r=MOD(n,2^8) 1110 LET s$=s$ & CHR$(r) 1120 LET n=(n-r)/2^8 1130 LET r=MOD(n,2^8) 1140 LET DWORD$=s$ & CHR$(r) 1150 END FUNCTION 1160 ! 外部関数定義 WORD$(16ビット整数化した文字列(2バイト)) 1170 EXTERNAL FUNCTION WORD$(n) 1180 OPTION ARITHMETIC NATIVE 1190 OPTION CHARACTER byte 1200 LET r=MOD(n,2^8) 1210 LET s$=CHR$(r) 1220 LET n=(n-r)/2^8 1230 LET r=MOD(n,2^8) 1240 LET WORD$=s$ & CHR$(r) 1250 END FUNCTION
文字列処理を利用して16ビット整数を生成しているので,実行速度は低速です。
十進BASIC 7.4.8(以降),BASIC Accerelator 0.9.3.0(以降)は,WORD$, DWORD$を組込関数として持つので,120行のDECLARE FUNCTION行と1000行以降を削除すると少し速くなります。
次のプログラムの9000行以降で定義されたモジュールWAVは,WAVファイルを読みます。
リニアPCM 16ビット(モノラルまたはステレオ)に対応します。
初めに,WAV.OPENでWAVファイルを指定します。
WAV.SIZEは波形データの個数,WAV.RATEはサンプリングレートです。
WAV.READ(L,R)で,波形データを1組ずつ読み取ります。
変数L,Rに,左右各チャンネルの波形データが−1以上1未満の値として取得されます。
(モノラルの場合には,L,Rに同じ数値が代入されます。)
100 OPTION ARITHMETIC NATIVE 110 DECLARE EXTERNAL SUB wav.open, wav.read, wav.close 120 DECLARE EXTERNAL NUMERIC wav.size, wav.rate, wav.NChannels 130 DECLARE NUMERIC i,L,R,t,d 140 DECLARE STRING FName$ 150 FILE GETNAME FName$, "WAV" 160 CALL wav.open (FName$) 170 PRINT FName$ 180 PRINT "サンプリングレート(Hz)", wav.rate 190 IF wav.NChannels=1 THEN PRINT "モノラル" ELSE PRINT "ステレオ" 200 PRINT "長さ(秒)", wav.size / wav.rate 210 LET d=1/32 220 SET WINDOW 0, d , -2, 2 230 FOR i=0 TO wav.size-1 240 LET t = i/wav.rate 250 LET t = MOD(t,d) 260 IF t < 1/wav.rate THEN 270 WAIT DELAY d 280 CLEAR 290 PLOT LINES 300 END if 310 CALL wav.read(L,R) 320 PLOT LINES :t,L+R; 330 NEXT i 340 CALL wav.close 350 END 360 9000 MODULE WAV 9010 MODULE OPTION ARITHMETIC NATIVE 9020 PUBLIC SUB OPEN, READ, CLOSE 9030 PUBLIC NUMERIC SIZE ! サンプル数。size/rateで時間になる 9040 PUBLIC NUMERIC RATE ! サンプリングレート 9050 PUBLIC NUMERIC nchannels ! チャンネル数 1または2 9060 SHARE STRING FNAME$ 9070 SHARE NUMERIC count 9080 SHARE FUNCTION DWORD, INT16 9090 SHARE FUNCTION Chars4$ 9100 SHARE CHANNEL #1 9110 LET count=0 9120 9130 EXTERNAL SUB OPEN(f$) 9140 DECLARE NUMERIC n,id,blocksize 9150 DECLARE STRING s$ 9160 OPEN #1: NAME f$, ACCESS INPUT 9170 LET s$=Chars4$ 9180 IF s$<>"RIFF" THEN CAUSE EXCEPTION 999 9190 LET n=DWORD ! これ以降のファイルサイズ(無視) 9200 LET s$=Chars4$ 9210 IF s$<>"WAVE" THEN CAUSE EXCEPTION 999 9220 LET s$=Chars4$ 9230 IF s$<>"fmt " THEN CAUSE EXCEPTION 999 9240 LET n=DWord 9250 IF n<>16 THEN CAUSE EXCEPTION 999 9260 LET id=int16 9270 IF id<>1 THEN CAUSE EXCEPTION 999 9280 LET nchannels =int16 ! チャンネル数 9290 LET Rate = dword ! サンプリングレート 9300 LET n=DWORD ! データ速度(無視) 9310 LET BlockSize=int16 ! ブロックサイズ 9320 LET n=int16 ! 8 or 16 9330 IF n<>16 THEN CAUSE EXCEPTION 998 9340 LET s$=Chars4$ 9350 IF s$<>"data" THEN CAUSE EXCEPTION 999 9360 LET SIZE=DWORD/BlockSize 9370 END SUB 9380 9390 EXTERNAL SUB READ (L, R) 9400 IF count < SIZE THEN 9410 LET L=int16/2^16 9420 IF nchannels=2 THEN 9430 LET R=int16/2^16 9440 ELSE 9450 LET R=L 9460 END IF 9470 LET count=count+1 9480 ELSE 9490 CAUSE EXCEPTION 997 9500 END if 9510 END SUB 9520 9530 EXTERNAL FUNCTION Chars4$ 9540 OPTION CHARACTER byte 9550 DECLARE STRING s$ 9560 CHARACTER INPUT #1: s$ 9570 CHARACTER INPUT #1: s$(2:2) 9580 CHARACTER INPUT #1: s$(3:3) 9590 CHARACTER INPUT #1: s$(4:4) 9600 LET Chars4$=s$ 9610 END FUNCTION 9620 9630 EXTERNAL FUNCTION DWord 9640 OPTION CHARACTER byte 9650 DECLARE NUMERIC n 9660 DECLARE STRING s$ 9670 CHARACTER INPUT #1: s$ 9680 LET n=ORD(s$) 9690 CHARACTER INPUT #1: s$ 9700 LET n=n + ORD(s$)*2^8 9710 CHARACTER INPUT #1: s$ 9720 LET n=n + ORD(s$)*2^16 9730 CHARACTER INPUT #1: s$ 9740 LET n=n + ORD(s$)*2^24 9750 LET DWord=n 9760 END FUNCTION 9770 9780 EXTERNAL FUNCTION Int16 9790 OPTION CHARACTER byte 9800 DECLARE NUMERIC n 9810 DECLARE STRING s$ 9820 CHARACTER INPUT #1: s$ 9830 LET n=ORD(s$) 9840 CHARACTER INPUT #1: s$ 9850 LET n=n+ORD(s$)*2^8 9860 IF n>=2^15 THEN LET n=n-2^16 9870 LET int16=n 9880 END FUNCTION 9890 9900 EXTERNAL SUB CLOSE 9910 CLOSE #1 9920 END SUB 9930 END MODULE
マイクロフォンなどの音源からWAVファイルを作成するのに,Windows95〜XPではWindowsアクセサリーのサウンドレコーダが使えます。
Windows Vista/7 でWAVファイルを作成したい場合は,次のフリーソフトが使えると思います(未テスト)。
Re:Sound - 帰ってきた サウンド レコーダー