グラフィックデモ - しばっち
2025/01/26 (Sun) 07:39:50
サンプルの文章にgnuutera2012or文句うさびょんさんの投稿ネタを使用しました。
OPTION ANGLE DEGREES
DIM MOV(4,4)
LET XSIZE=1000
LET YSIZE=600
CALL GINIT(XSIZE,YSIZE)
SET WINDOW -XSIZE/2,XSIZE/2,-YSIZE/2,YSIZE/2
DIM A$(50)
FOR N=1 TO 50
READ IF MISSING THEN EXIT FOR:A$(N)
NEXT N
LET YMOVE=.002
SET TEXT JUSTIFY "CENTER","HALF"
SET TEXT COLOR COLORINDEX(0,0,0)
LET HEIGHT=12
SET TEXT HEIGHT HEIGHT
SET TEXT BACKGROUND "OPAQUE"
MAT MOV=IDN
LET MOV(1,4)=XMOVE
LET MOV(2,4)=YMOVE
LET MOV(3,4)=ZMOVE
FOR I=1 TO 85
SET DRAW MODE HIDDEN
CLEAR
FOR J=I TO 1 STEP -1
IF J=1 AND I<=N THEN
SET DRAW MODE EXPLICIT
FOR K=1 TO LEN(A$(I-J+1))
IF I<=N THEN DRAW WORD(A$(I)(1:K),0,-YSIZE/2+(HEIGHT+5)*(J+6)) WITH MOV
NEXT K
ELSE
IF I-J+1<=N AND -YSIZE/2+(HEIGHT+5)*J<YSIZE/2 THEN DRAW WORD(A$(I-J+1),0,-YSIZE/2+(HEIGHT+5)*(J+6)) WITH MOV
END IF
NEXT J
SET DRAW MODE EXPLICIT
WAIT DELAY .1
NEXT I
DATA "昔々、あるところにお殿様とお姫様がいました。"
DATA "お殿様は山へ鷹狩りに、お姫様は川へお茶会に行きました。"
DATA "お姫様が洗濯をしていると、川から大きなピーチパイがえんやーとっとえんやーとっとと流れてきました。"
DATA "お姫様はお殿様とピーチパイを食べようと思って、大きなピーチパイを家に持ち帰りました。"
DATA "山から帰ってきたお殿様は、大きなピーチパイだと早速包丁で切ろうとしたところ"
DATA "ピーチパイの中から女の赤ん坊が元気よく飛び出してきました。"
DATA "お殿様は赤ん坊に桃姫と名づけました。"
DATA "桃姫はすくすくと育っていき、やがて立派に育つと"
DATA "お殿様とお姫様にダンサーヶ島へダンサー勝負に行きたいと申し出ました。"
DATA "お殿様とお姫様は、恐ろしいダンサーが住んでいるダンサーヶ島へ"
DATA "桃姫を行かせまいと必死になだめますが、桃姫は頑としてききません。"
DATA "仕方なくお殿様は桃姫にLEDサイネージと蛍光塗料を"
DATA "お姫様は、衣装と日本一の旗を揃え桃姫に授けました。"
DATA "桃姫が出発する日に、お姫様は道中の腹ごしらえにと"
DATA "プロテインを桃姫に持たせました。"
DATA "桃姫はお殿様、お姫様に「行って参ります」と元気よく出発しました。"
DATA "桃姫が歩いていると、道の向かいからケンが「ヒャッハー!」桃姫さん"
DATA "お腰につけたプロテインを一つくれたら家来になりましょう「ヒャッハー!」と頼むので"
DATA "桃姫はケンにプロテインを一つ分けてやりました。"
DATA "桃姫とケンが道を歩いて行くと、道の向かいからモンタナが「あらよっと!」桃姫さん"
DATA "お腰につけたプロテインを一つくれたら家来になりましょう「あらよっと!」と頼むので"
DATA "桃姫はモンタナにもプロテインを一つ分けてやりました。"
DATA "桃姫とケンとモンタナが道を歩いて行くと、道の向かいから太郎が(♪♪♪♪♪)桃姫さん"
DATA "お腰につけたプロテインを一つくれたら家来になりましょう(♪♪♪♪♪)と頼むので"
DATA "桃姫は太郎にもプロテインを一つ分けてやりました。"
DATA "こうしてケン、モンタナ、太郎をお供に従えた桃姫は、舟に乗って"
DATA "ダンサーヶ島に着きました。"
DATA "ダンサーヶ島では恐ろしいダンサー達が宴の真っ最中。"
DATA "ダンサー共、この桃姫が成敗してくれる。"
DATA "桃姫はLEDサイネージと蛍光塗料でダンサー達に迫ります。"
DATA "ケン、モンタナ、太郎もそこへ襲いかかります。"
DATA "ケンはダンサーに握手します。"
DATA "モンタナはダンサーに握手します。"
DATA "太郎は空からダンサーと握手します。"
DATA "さすがのダンサー共も降参しました。"
DATA "桃姫さん。助けてください。"
DATA "ダンサーヶ島の宝物を全部差し上げます。"
DATA "もう悪いことは致しません。"
DATA "必死でダンサー達が頼むので、桃姫は"
DATA "「良いだろう。もうダンスはするなよ。」とダンサー達を許してやりました。"
DATA "こうして、宝物を舟に積んでダンサー達に見送られながら"
DATA "桃姫、ケン、モンタナ、太郎の一行はダンサーヶ島をあとにしました。"
DATA "桃姫、ケン、モンタナ、太郎がお殿様とお姫様の家に着くと"
DATA "お殿様とお姫様は大層喜びました。"
DATA "桃姫は、ダンサーヶ島でダンサー達を成敗したこと"
DATA "ダンサー達にもらった宝物のことを話しました。"
DATA "ダンサー達にもらった宝物で桃姫、お殿様、お姫様"
DATA "ケン、モンタナ、太郎はいつまでも楽しく暮らしたということです。"
DATA "めでたしめでたし。"
END
EXTERNAL PICTURE WORD(A$,XS,YS)
DIM M(4,4)
MAT M=TRANSFORM
IF DET(M)<>0 THEN
PLOT LETTERS, AT XS,YS:A$
END IF
END PICTURE
EXTERNAL SUB GINIT(XSIZE,YSIZE)
SET BITMAP SIZE XSIZE,YSIZE
SET WINDOW 0,XSIZE-1,0,YSIZE-1
SET POINT STYLE 1
SET COLOR MODE "NATIVE"
CLEAR
END SUB
多次元配列 - しばっち
2025/01/01 (Wed) 07:51:37
十進BASICでは独自拡張で4次元までの配列が使える。
しかしながら5次元以上の配列が定義できないわけではない。
その要となるのが1次元化である。
まず、2次元配列を1次元化してみる。
配列サイズをXSIZE,YSIZEとする。
各添え字範囲を0~XSIZE-1,0~YSIZE-1とすると
DIM X(0 TO XSIZE-1,0 TO YSIZE-1) この2次元配列定義を1次元化すると
DIM X(0 TO XSIZE*YSIZE-1) となる。
LET I=1 ! 0<=I<=XSIZE-1
LET J=0 ! 0<=J<=YSIZE-1
とすると
LET X(XSIZE*IP(J)+IP(I))=2
又は
LET X(YSIZE*IP(I)+IP(J))=2
とできる。
各添え字範囲を1~XSIZE,1~YSIZEとすると
DIM Y(XSIZE*YSIZE)
と定義でき、
LET I=1 ! 1<=I<=XSIZE
LET J=1 ! 1<=J<=YSIZE
として
LET Y(XSIZE*IP(J-1)+IP(I))=2
又は
LET Y(YSIZE*IP(I-1)+IP(J))=2
となる。
また、添え字範囲を
LET MIN1=-3
LET MAX1=2
LET MIN2=-3
LET MAX2=2
のようにすると
DIM W(MIN1 TO MAX1,MIN2 TO MAX2) これは
DIM W((MAX2-MIN2+1)*(MAX1-MIN1+1))
と定義できる。
LET I=-2 ! MIN1<=I<=MAX1
LET J=1 ! MIN2<=J<=MAX2
として
LET W((MAX1-MIN1+1)*IP(J-MIN2)+IP(I-MIN1+1))=3
とできる。
これを拡張していくと5次元配列は
LET MIN1=-3
LET MAX1=2
LET MIN2=-3
LET MAX2=2
LET MIN3=-3
LET MAX3=2
LET MIN4=-3
LET MAX4=2
LET MIN5=-3
LET MAX5=2
!!DIM X(MIN1 TO MAX1,MIN2 TO MAX2,MIN3 TO MAX3,MIN4 TO MAX4,MIN5 TO MAX5)
DIM X((MAX5-MIN5+1)*(MAX4-MIN4+1)*(MAX3-MIN3+1)*(MAX2-MIN2+1)*(MAX1-MIN1+1))
LET I=-1 ! MIN1<=I<=MAX1
LET J=0 ! MIN2<=J<=MAX2
LET K=2 ! MIN3<=K<=MAX3
LET L=1 ! MIN4<=L<=MAX4
LET M=-2 ! MIN5<=M<=MAX5
LET A1=MAX1-MIN1+1
LET A2=MAX2-MIN2+1
LET A3=MAX3-MIN3+1
LET A4=MAX4-MIN4+1
LET A5=MAX5-MIN5+1
LET C=A1*A2*A3*A4*IP(M-MIN5)+A1*A2*A3*IP(L-MIN4)+A1*A2*IP(K-MIN3)+A1*IP(J-MIN2)+IP(I-MIN1+1)
LET X(C)=5
PRINT A(I,J,K,L,M)
FUNCTION A(I,J,K,L,M)
IF I<MIN1 THEN LET I=MIN1
IF J<MIN2 THEN LET J=MIN2
IF K<MIN3 THEN LET K=MIN3
IF L<MIN4 THEN LET L=MIN4
IF M<MIN5 THEN LET M=MIN5
IF I>MAX1 THEN LET I=MAX1
IF J>MAX2 THEN LET J=MAX2
IF K>MAX3 THEN LET K=MAX3
IF L>MAX4 THEN LET L=MAX4
IF M>MAX5 THEN LET M=MAX5
LET A1=MAX1-MIN1+1
LET A2=MAX2-MIN2+1
LET A3=MAX3-MIN3+1
LET A4=MAX4-MIN4+1
LET A5=MAX5-MIN5+1
LET C=A1*A2*A3*A4*IP(M-MIN5)+A1*A2*A3*IP(L-MIN4)+A1*A2*IP(K-MIN3)+A1*IP(J-MIN2)+IP(I-MIN1+1)
LET A=X(C)
END FUNCTION
END
非常に式が長くなるので読み出しに関して内部関数で上記のように定義すれば
5次元配列のように使用できる。
添え字に使用する変数が実数値の時はおかしなことになるのでIP()で整数値に丸めます。
また、添え字が範囲外になる時、エラーとしてもいいのですがここでは範囲内に収まるようにしています。
6次元以上も同様に定義できます。
Re: 多次元配列 - nagram
2025/01/16 (Thu) 22:13:01
一般化してみました.
既存の配列 A を, bound(m,2) で下限,上限を設定し m次元の仮想配列に再定義する.
仮想配列の次元は何次元でもよい. Aの次元より大きくても小さくてもよい. (次元が同じ場合は MAT REDIM と同等)
仮想配列の全要素数は, Aの全要素数と等しくなくてもよい. (超えた場合はエラー)
◎ 外部関数 remat* … subscript の添字で指定した要素が仮想配列の何番目にあたるかを算出し,
同順位の A の要素を戻り値とする. (remat* の * は 1~4 の数字)
・ remat1(A,bound,subscript)
・ remat2(A,bound,subscript)
・ remat3(A,bound,subscript)
・ remat4(A,bound,subscript)
A … 元の配列. remat に続く数字の次元を持つ.
bound … 2次元配列 bound(m,2). m次元の仮想配列の各次元の下限,上限.
subscript … 1次元配列 subscript(m). 値を求めたい仮想配列の 1~m次の添字を指定.
配列要素の順位は次元の下位から変化する. DIM A(2,2,3) と定義された配列の順位は,
A(1,1,1),A(1,1,2),A(1,1,3),A(1,2,1),A(1,2,2),A(1,2,3),A(2,1,1),A(2,1,2),A(2,1,3),A(2,2,1),A(2,2,2),A(2,2,3)
◎ 外部副プログラム remat_print* … 仮想配列を一括出力する. (remat_print* の * は 1~4 の数字)
・ remat_print1(A,bound,width,intvl)
・ remat_print2(A,bound,width,intvl)
・ remat_print3(A,bound,width,intvl)
・ remat_print4(A,bound,width,intvl)
A … 元の配列. remat_print に続く数字の次元を持つ.
bound … 2次元配列 bound(m,2). m次元の仮想配列の各次元の下限,上限.
width … 仮想配列の出力欄の幅の仕様. width=1 は MAT PRINT V; に, width=2 は MAT PRINT V に相当.
intvl … 3次元以上(m>=3)の仮想配列の出力で, 間隔をあける仕様.
intvl=1 … 間隔を1行に固定 , intvl=2 … 第 j次元内の区切りで (m-j-1)行の間隔をあける
([参考] 十進BASIC の MAT PRINT で4次元配列を出力すると, 第1次元内・第2次元内の間隔は1行固定)
DECLARE EXTERNAL FUNCTION remat1, remat2, remat3, remat4
DECLARE EXTERNAL SUB remat_print1, remat_print2, remat_print3, remat_print4, mat_init
DECLARE NUMERIC m,j
DIM X(1 TO 3, 5 TO 6, 11 TO 15, 31 TO 39) ! X は 4次元配列
CALL mat_init(X) ! 元の配列の値を決定
PRINT SIZE(X,1);SIZE(X,2);SIZE(X,3);SIZE(X,4) ;" 元の配列 X の各次元のサイズ"
MAT PRINT X;
PRINT
LET m=5 ! 仮想配列の次元
DIM virtual(m,2), index(m)
DATA 1,2, 5,7, 11,12, -8,-5, 21,25 ! 仮想配列の下限,上限 (サイズは 2,3,2,4,5)
MAT READ virtual ! DIM V(1 TO 2, 5 TO 7, 11 TO 12, -8 TO -5, 21 TO 25)
PRINT "仮想配列の下限,上限"
MAT PRINT virtual;
DATA 2,7,11,-6,24 ! 値を求めたい仮想配列の指標
MAT READ index
PRINT "仮想配列の添え字を指定"
MAT PRINT index;
PRINT "仮想配列の下限を 1とした位置"
FOR j=1 TO m
PRINT index(j)-virtual(j,1)+1;
NEXT j
PRINT
PRINT
PRINT remat4(X,virtual,index) ;" 関数 remat4 の戻り値"
PRINT
PRINT
FOR j=1 TO m
PRINT virtual(j,2)-virtual(j,1)+1;
NEXT j
PRINT " 仮想配列の各次元のサイズ"
CALL remat_print4(X,virtual,1,2) ! 仮想配列の一括出力
END
EXTERNAL FUNCTION remat1(A(),bound(,),subscript()) ! 1次元配列 A を bound で仮想配列に再定義し,
DECLARE EXTERNAL SUB element_order ! subscript で指定した値
DECLARE NUMERIC n
CALL element_order(SIZE(A),bound,subscript,n)
!PRINT " A(";STR$(n);")" ! 元の配列での位置(下限を1とする)
LET remat1=A(LBOUND(A)+n-1)
END FUNCTION
EXTERNAL FUNCTION remat2(A(,),bound(,),subscript()) ! 2次元配列 A を bound で仮想配列に再定義し,
DECLARE EXTERNAL SUB element_order ! subscript で指定した値
DECLARE NUMERIC n,sz2,a2
CALL element_order(SIZE(A),bound,subscript,n)
LET sz2=SIZE(A,2)
LET a2=MOD(n,sz2)
IF a2=0 THEN LET a2=sz2
!PRINT n;" A(";CEIL(n/sz2);",";a2;")" ! 元の配列での位置(下限を1とする)
LET remat2=A(LBOUND(A,1)+CEIL(n/sz2)-1,LBOUND(A,2)+a2-1)
END FUNCTION
EXTERNAL FUNCTION remat3(A(,,),bound(,),subscript()) ! 3次元配列 A を bound で仮想配列に再定義し,
DECLARE EXTERNAL SUB element_order ! subscript で指定した値
DECLARE NUMERIC n,sz2,sz3,a2,a3
CALL element_order(SIZE(A),bound,subscript,n)
LET sz3=SIZE(A,3)
LET a3=MOD(n,sz3)
LET sz2=SIZE(A,2)
LET a2=MOD(CEIL(n/sz3),sz2)
IF a3=0 THEN LET a3=sz3
IF a2=0 THEN LET a2=sz2
!PRINT n;" A(";CEIL(n/(sz2*sz3));",";a2;",";a3;")" ! 元の配列での位置(下限を1とする)
LET remat3=A(LBOUND(A,1)+CEIL(n/(sz2*sz3))-1,LBOUND(A,2)+a2-1,LBOUND(A,3)+a3-1)
END FUNCTION
EXTERNAL FUNCTION remat4(A(,,,),bound(,),subscript()) ! 4次元配列 A を bound で仮想配列に再定義し,
DECLARE EXTERNAL SUB element_order ! subscript で指定した値
DECLARE NUMERIC n,sz2,sz3,sz4,a2,a3,a4
CALL element_order(SIZE(A),bound,subscript,n)
LET sz4=SIZE(A,4)
LET a4=MOD(n,sz4)
LET sz3=SIZE(A,3)
LET a3=MOD(CEIL(n/sz4),sz3)
LET sz2=SIZE(A,2)
LET a2=MOD(CEIL(n/(sz3*sz4)),sz2)
IF a4=0 THEN LET a4=sz4
IF a3=0 THEN LET a3=sz3
IF a2=0 THEN LET a2=sz2
!PRINT n;" A(";CEIL(n/(sz2*sz3*sz4));",";a2;",";a3;",";a4;")" ! 元の配列での位置(下限を1とする)
LET remat4=A(LBOUND(A,1)+CEIL(n/(sz2*sz3*sz4))-1,LBOUND(A,2)+a2-1,LBOUND(A,3)+a3-1,LBOUND(A,4)+a4-1)
END FUNCTION
EXTERNAL SUB element_order(sza,bd(,),ss(),n) ! 仮想配列中のssで指定した順位 → n
DECLARE NUMERIC m,sr,sz,j
LET m=SIZE(bd,1) ! 仮想配列の次元数
IF m<>SIZE(ss) OR SIZE(bd,2)<>2 THEN CAUSE EXCEPTION 6001 ! 配列の寸法の誤り
FOR j=1 TO m
LET bd(j,1)=ROUND(bd(j,1))
LET bd(j,2)=ROUND(bd(j,2))
LET ss(j)=ROUND(ss(j))
NEXT j
LET n=ss(m)-bd(m,1)+1
LET sr=bd(m,2)-bd(m,1)+1
IF ss(m)<bd(m,1) OR ss(m)>bd(m,2) OR sr<=0 THEN CAUSE EXCEPTION 2001 ! 配列の添字が範囲外
FOR j=m-1 TO 1 STEP -1
LET sz=bd(j,2)-bd(j,1)+1
IF ss(j)<bd(j,1) OR ss(j)>bd(j,2) OR sz<=0 THEN CAUSE EXCEPTION 2001 ! 配列の添字が範囲外
LET n=n+sr*(ss(j)-bd(j,1))
LET sr=sr*sz ! sr=仮想配列の下位からj次までの要素数
NEXT j
IF sr>sza THEN CAUSE EXCEPTION 5001 ! 仮想配列の全要素数が, 元の配列Aの全要素数より多い
END SUB
EXTERNAL SUB remat_print1(A(),bound(,),width,intvl) ! 元の配列が1次元である仮想配列を一括出力
DECLARE EXTERNAL SUB elements
DECLARE NUMERIC m, m1,k, i1, j
LET m=SIZE(bound,1) ! 仮想配列の次元
DIM r(m)
CALL elements(SIZE(A),bound,m,r)
IF intvl=2 THEN LET m1=1 ELSE LET m1=m-1
LET k=0
FOR i1=LBOUND(A) TO UBOUND(A)
LET k=k+1
IF width=1 THEN PRINT A(i1); ELSE PRINT A(i1),
FOR j=m TO m1 STEP -1
IF MOD(k,r(j))=0 THEN
PRINT
IF k=r(1) THEN EXIT SUB
ELSE
EXIT FOR
END IF
NEXT j
NEXT i1
END SUB
EXTERNAL SUB remat_print2(A(,),bound(,),width,intvl) ! 元の配列が2次元である仮想配列を一括出力
DECLARE EXTERNAL SUB elements
DECLARE NUMERIC m, m1,k, i1,i2, j
LET m=SIZE(bound,1) ! 仮想配列の次元
DIM r(m)
CALL elements(SIZE(A),bound,m,r)
IF intvl=2 THEN LET m1=1 ELSE LET m1=m-1
LET k=0
FOR i1=LBOUND(A,1) TO UBOUND(A,1)
FOR i2=LBOUND(A,2) TO UBOUND(A,2)
LET k=k+1
IF width=1 THEN PRINT A(i1,i2); ELSE PRINT A(i1,i2),
FOR j=m TO m1 STEP -1
IF MOD(k,r(j))=0 THEN
PRINT
IF k=r(1) THEN EXIT SUB
ELSE
EXIT FOR
END IF
NEXT j
NEXT i2
NEXT i1
END SUB
EXTERNAL SUB remat_print3(A(,,),bound(,),width,intvl) ! 元の配列が3次元である仮想配列を一括出力
DECLARE EXTERNAL SUB elements
DECLARE NUMERIC m, m1,k, i1,i2,i3, j
LET m=SIZE(bound,1) ! 仮想配列の次元
DIM r(m)
CALL elements(SIZE(A),bound,m,r)
IF intvl=2 THEN LET m1=1 ELSE LET m1=m-1
LET k=0
FOR i1=LBOUND(A,1) TO UBOUND(A,1)
FOR i2=LBOUND(A,2) TO UBOUND(A,2)
FOR i3=LBOUND(A,3) TO UBOUND(A,3)
LET k=k+1
IF width=1 THEN PRINT A(i1,i2,i3); ELSE PRINT A(i1,i2,i3),
FOR j=m TO m1 STEP -1
IF MOD(k,r(j))=0 THEN
PRINT
IF k=r(1) THEN EXIT SUB
ELSE
EXIT FOR
END IF
NEXT j
NEXT i3
NEXT i2
NEXT i1
END SUB
EXTERNAL SUB remat_print4(A(,,,),bound(,),width,intvl) ! 元の配列が4次元である仮想配列を一括出力
DECLARE EXTERNAL SUB elements
DECLARE NUMERIC m, m1,k, i1,i2,i3,i4, j
LET m=SIZE(bound,1) ! 仮想配列の次元
DIM r(m)
CALL elements(SIZE(A),bound,m,r)
IF intvl=2 THEN LET m1=1 ELSE LET m1=m-1
LET k=0
FOR i1=LBOUND(A,1) TO UBOUND(A,1)
FOR i2=LBOUND(A,2) TO UBOUND(A,2)
FOR i3=LBOUND(A,3) TO UBOUND(A,3)
FOR i4=LBOUND(A,4) TO UBOUND(A,4)
LET k=k+1
IF width=1 THEN PRINT A(i1,i2,i3,i4); ELSE PRINT A(i1,i2,i3,i4),
FOR j=m TO m1 STEP -1
IF MOD(k,r(j))=0 THEN
PRINT
IF k=r(1) THEN EXIT SUB
ELSE
EXIT FOR
END IF
NEXT j
NEXT i4
NEXT i3
NEXT i2
NEXT i1
END SUB
EXTERNAL SUB elements(sza,bb(,),m,r())
DECLARE NUMERIC j
IF SIZE(bb,2)<>2 THEN CAUSE EXCEPTION 6001 ! 配列の寸法の誤り
FOR j=1 TO m
LET bb(j,1)=ROUND(bb(j,1))
LET bb(j,2)=ROUND(bb(j,2))
NEXT j
LET r(m)=bb(m,2)-bb(m,1)+1
IF r(m)<=0 THEN CAUSE EXCEPTION 2001 ! 仮想配列の添字が範囲外
IF m>=2 THEN
FOR j=m-1 TO 1 STEP -1
LET r(j)=r(j+1)*(bb(j,2)-bb(j,1)+1)
IF r(j)<=0 THEN CAUSE EXCEPTION 2001 ! 仮想配列の添字が範囲外
NEXT j
END IF
IF r(1)>sza THEN CAUSE EXCEPTION 5001 ! 仮想配列の全要素数が, 元の配列の全要素数より多い
END SUB
EXTERNAL SUB mat_init(A(,,,)) ! 元の配列の値を決定
DECLARE NUMERIC L(4), i, i1,i2,i3,i4
FOR i=1 TO 4
LET L(i)=LBOUND(A,i)
NEXT i
FOR i1=1 TO SIZE(A,1)
FOR i2=1 TO SIZE(A,2)
FOR i3=1 TO SIZE(A,3)
FOR i4=1 TO SIZE(A,4)
LET A(L(1)+i1-1,L(2)+i2-1,L(3)+i3-1,L(4)+i4-1)=1000*i1+100*i2+10*i3+i4
! LET A(L(1)+i1-1,L(2)+i2-1,L(3)+i3-1,L(4)+i4-1)=INT(10000*RND)
NEXT i4
NEXT i3
NEXT i2
NEXT i1
END SUB
アニメーション - しばっち
2025/01/12 (Sun) 08:01:37
アニメーション
https://graphtoy.com/
SET COLOR MIX(0) 0,0,0
CLEAR
SET WINDOW -8,8,-8,8
FOR T=0 TO 100 STEP 1/2
SET LINE COLOR 12
FOR X=-8 TO 8 STEP 1/16
PLOT LINES:X,F1(X,T);
NEXT X
PLOT LINES
SET LINE COLOR 6
FOR X=-8 TO 8 STEP 1/16
PLOT LINES:X,F2(X,T);
NEXT X
PLOT LINES
SET LINE COLOR 3
FOR X=-8 TO 8 STEP 1/16
PLOT LINES:X,F3(X,T);
NEXT X
PLOT LINES
SET LINE COLOR 2
FOR X=-8 TO 8 STEP 1/16
PLOT LINES:X,F4(X,T);
NEXT X
PLOT LINES
SET LINE COLOR 4
FOR X=-8 TO 8 STEP 1/16
PLOT LINES:X,F5(X,T);
NEXT X
PLOT LINES
SET DRAW MODE EXPLICIT
WAIT DELAY 1/10
SET DRAW MODE HIDDEN
CLEAR
NEXT T
END
EXTERNAL FUNCTION F1(X,T)
LET F1=2+2*SIN(INT(X+T)*4321)
END FUNCTION
EXTERNAL FUNCTION F2(X,T)
LET F2=MAX(SQR(8^2-X^2),F1(X,T))
END FUNCTION
EXTERNAL FUNCTION F3(X,T)
LET F3=-1
END FUNCTION
EXTERNAL FUNCTION F4(X,T)
LET F4=-2
END FUNCTION
EXTERNAL FUNCTION F5(X,T)
LET F5=0
END FUNCTION
--------------------------------------------------------------------------------
SET WINDOW -10,10,-10,10
SET COLOR MIX(0) 0,0,0
CLEAR
FOR T=0 TO 100 STEP 1/4
SET LINE COLOR 12
FOR X=-8 TO 8 STEP 1/8
WHEN EXCEPTION IN
PLOT LINES:X,F1(X,T);
USE
PLOT LINES
END WHEN
NEXT X
PLOT LINES
SET LINE COLOR 6
FOR X=-8 TO 8 STEP 1/8
WHEN EXCEPTION IN
PLOT LINES:X,F2(X,T);
USE
PLOT LINES
END WHEN
NEXT X
PLOT LINES
SET LINE COLOR 3
FOR X=-8 TO 8 STEP 1/8
WHEN EXCEPTION IN
PLOT LINES:X,F3(X,T);
USE
PLOT LINES
END WHEN
NEXT X
PLOT LINES
SET LINE COLOR 2
FOR X=-8 TO 8 STEP 1/8
WHEN EXCEPTION IN
PLOT LINES:X,F4(X,T);
USE
PLOT LINES
END WHEN
NEXT X
PLOT LINES
SET LINE COLOR 14
FOR X=-8 TO 8 STEP 1/8
WHEN EXCEPTION IN
PLOT LINES:X,F5(X,T);
USE
PLOT LINES
END WHEN
NEXT X
PLOT LINES
SET LINE COLOR 4
FOR X=-8 TO 8 STEP 1/8
WHEN EXCEPTION IN
PLOT LINES:X,F6(X,T);
USE
PLOT LINES
END WHEN
NEXT X
PLOT LINES
SET DRAW MODE EXPLICIT
WAIT DELAY 1/8
SET DRAW MODE HIDDEN
CLEAR
NEXT T
END
EXTERNAL FUNCTION F1(X,T)
LET F1=SQR(8^2-X^2)
END FUNCTION
EXTERNAL FUNCTION F2(X,T)
LET F2=-F1(X,T)
END FUNCTION
EXTERNAL FUNCTION F3(X,T)
LET F3=7/2-SQR(3^2-(ABS(X)-3.5)^2)
END FUNCTION
EXTERNAL FUNCTION F4(X,T)
LET F4=7/2+SQR(3^2-(ABS(X)-3.5)^2)/2
END FUNCTION
EXTERNAL FUNCTION F5(X,T)
LET F5=3+SQR(1-(ABS(X+SIN(4*T)/2)-3)^2)*2/3
END FUNCTION
EXTERNAL FUNCTION F6(X,T)
LET F6=-3-SQR(5^2-X^2)*(1/4+POW(.5+.5*SIN(2*PI*T),6)/10)
END FUNCTION
EXTERNAL FUNCTION POW(X,N)
LET POW=X^N
END FUNCTION
数独 - 永野護
2025/01/07 (Tue) 23:53:15
6×6の数独を解くコードが完成しません。
どこがいけないのでしょうか。
ご教示くだされば幸いです。
DECLARE FUNCTION IsValid
DECLARE FUNCTION SolveSudoku
OPTION BASE 0
DIM Board(5, 5)
!' サンプルの6x6数独問題 (0は空きマス)
DATA 1, 0, 3, 0, 0, 0
DATA 0, 0, 0, 0, 0, 4
DATA 0, 0, 0, 0, 2, 0
DATA 0, 5, 0, 0, 0, 0
DATA 3, 0, 0, 0, 0, 0
DATA 0, 0, 0, 4, 0, 0
!' 盤面を初期化
FOR i = 0 TO 5
FOR j = 0 TO 5
READ Board(i, j)
NEXT j
NEXT i
PRINT "元の盤面:"
FOR i = 0 TO 5
FOR j = 0 TO 5
IF Board(i, j) = 0 THEN
PRINT ".";
ELSE
PRINT Board(i, j);
END IF
NEXT j
PRINT
NEXT i
IF SolveSudoku = true THEN
PRINT "解けた盤面:"
FOR i = 0 TO 5
FOR j = 0 TO 5
PRINT Board(i, j);
NEXT j
PRINT
NEXT i
ELSE
PRINT "解けませんでした。"
END IF
FUNCTION IsValid (Row, Col, Num)
!' 行と列をチェック
FOR i = 0 TO 5
IF Board(Row, i) = Num THEN
LET IsValid = 0
EXIT FUNCTION
END IF
IF Board(i, Col) = Num THEN
LET IsValid = 0
EXIT FUNCTION
END IF
NEXT i
LET IsValid = true
END FUNCTION
FUNCTION SolveSudoku
FOR Row = 0 TO 5
FOR Col = 0 TO 5
IF Board(Row, Col) = 0 THEN
FOR Num = 1 TO 6
IF IsValid(Row, Col, Num) = true THEN
LET Board(Row, Col) = Num
IF SolveSudoku = true THEN
LET SolveSudoku = true
EXIT FUNCTION
END IF
LET Board(Row, Col) = 0
END IF
LET SolveSudoku = 0
NEXT Num
LET SolveSudoku = 0
EXIT FUNCTION
END IF
NEXT Col
NEXT Row
LET SolveSudoku = true
END FUNCTION
END
Re: 数独 - SHIRAISHI Kazuo
2025/01/08 (Wed) 08:01:25
とりあえず気になったのが,変数trueの値を変える文が見当たらないことです。十進BASICでは変数の初期値は0に設定されています。
Re: 数独 - しばっち
2025/01/12 (Sun) 07:59:52
次のプログラムはバックトラック法(後戻り法)と呼ばれる手法を
使用しています。
このバックトラック法は今回のようなパズル問題を解くのに有効な
方法ですがプログラミング初心者には少々難しいかもしれません。
この手法は覚えておいて損はないと思います。
https://ja.wikipedia.org/wiki/バックトラッキング
https://www.cc.kyoto-su.ac.jp/~yamada/ap/backtrack.html
http://www.tommylab.ynu.ac.jp/lecture/Algorithm/10/10.pdf
https://sevendays-study.com/algorithm/ex-day4.html
内部関数、内部副プログラムのままではうまくいかず
外部関数、外部副プログラムとするとうまくいったので
パックトラック法を実装する時は外部関数や外部副プログラム
として定義した方がいいかと思います。
OPTION BASE 0
PUBLIC NUMERIC Board(5, 5),True,False,COUNT
!' サンプルの6x6数独問題 (0は空きマス)
DATA 1, 0, 3, 0, 0, 0
DATA 0, 0, 0, 0, 0, 4
DATA 0, 0, 0, 0, 2, 0
DATA 0, 5, 0, 0, 0, 0
DATA 3, 0, 0, 0, 0, 0
DATA 0, 0, 0, 4, 0, 0
LET True=1
LET False=0
!' 盤面を初期化
FOR i = 0 TO 5
FOR j = 0 TO 5
READ Board(i, j)
NEXT j
NEXT i
PRINT "元の盤面:"
FOR i = 0 TO 5
FOR j = 0 TO 5
IF Board(i, j) = 0 THEN
PRINT ".";
ELSE
PRINT STR$(Board(i, j));
END IF
NEXT j
PRINT
NEXT i
CALL SolveSudoku(0)
END
EXTERNAL FUNCTION IsValid (Row, Col, Num)
!' 行と列をチェック
FOR i = 0 TO 5
IF Board(Row, i) = Num THEN
LET IsValid = False
EXIT FUNCTION
END IF
IF Board(i, Col) = Num THEN
LET IsValid = False
EXIT FUNCTION
END IF
NEXT i
LET IsValid = True
END FUNCTION
EXTERNAL SUB SolveSudoku(N)
IF N>35 THEN
LET COUNT=COUNT+1
PRINT "解けた盤面:";COUNT
FOR i = 0 TO 5
FOR j = 0 TO 5
PRINT Board(i, j);
NEXT j
PRINT
NEXT i
IF COUNT=100 THEN STOP
ELSE
LET Col=MOD(N,6)
LET Row=INT(N/6)
IF Board(Row, Col) = 0 THEN
FOR Num = 1 TO 6
IF IsValid(Row, Col, Num) = True THEN
LET Board(Row, Col) = Num
CALL SolveSudoku(N+1) ! 再帰呼び出し
LET Board(Row, Col) = 0
END IF
NEXT Num
ELSE
CALL SolveSudoku(N+1) ! 再帰呼び出し
END IF
END IF
END SUB
再帰呼び出しを使用することで多重ループ(ここではFORループ29個)を代替させることができます。
※下記プログラム参照
-----------------------------------------------------------------------------------
上記のプログラムを総当り法(※厳密には少し違う)で書き換えてみました。
6^29(36845653286788892983296)回という途方もない回数のループですが
if文によってループが制御されています。
プログラム的にやっていることは上記のプログラムと同じです。(プログラムの書き方が違うだけ!?)
OPTION BASE 0
DIM Board(5, 5)
!' サンプルの6x6数独問題 (0は空きマス)
DATA 1, 0, 3, 0, 0, 0
DATA 0, 0, 0, 0, 0, 4
DATA 0, 0, 0, 0, 2, 0
DATA 0, 5, 0, 0, 0, 0
DATA 3, 0, 0, 0, 0, 0
DATA 0, 0, 0, 4, 0, 0
LET True=1
LET False=0
!' 盤面を初期化
FOR i = 0 TO 5
FOR j = 0 TO 5
READ Board(i, j)
NEXT j
NEXT i
PRINT "元の盤面:"
FOR i = 0 TO 5
FOR j = 0 TO 5
IF Board(i, j) = 0 THEN
PRINT ".";
ELSE
PRINT STR$(Board(i, j));
END IF
NEXT j
PRINT
NEXT i
FOR A1=1 TO 6
IF IsValid (0,1,A1)=True THEN
LET Board(0,1)=A1
FOR A2=1 TO 6
IF IsValid (0, 3, A2)=True THEN
LET Board(0,3)=A2
FOR A3=1 TO 6
IF IsValid (0, 4, A3)=True THEN
LET Board(0,4)=A3
FOR A4=1 TO 6
IF IsValid (0, 5, A4)=True THEN
LET Board(0,5)=A4
FOR B1=1 TO 6
IF IsValid (1, 0, B1)=True THEN
LET Board(1,0)=B1
FOR B2=1 TO 6
IF IsValid (1, 1, B2)=True THEN
LET Board(1,1)=B2
FOR B3=1 TO 6
IF IsValid (1, 2, B3)=True THEN
LET Board(1,2)=B3
FOR B4=1 TO 6
IF IsValid (1, 3, B4)=True THEN
LET Board(1,3)=B4
FOR B5=1 TO 6
IF IsValid (1, 4, B5)=True THEN
LET Board(1,4)=B5
FOR C1=1 TO 6
IF IsValid (2, 0, C1)=True THEN
LET Board(2,0)=C1
FOR C2=1 TO 6
IF IsValid (2, 1, C2)=True THEN
LET Board(2,1)=C2
FOR C3=1 TO 6
IF IsValid (2, 2, C3)=True THEN
LET Board(2,2)=C3
FOR C4=1 TO 6
IF IsValid (2, 3, C4)=True THEN
LET Board(2,3)=C4
FOR C5=1 TO 6
IF IsValid (2, 5, C5)=True THEN
LET Board(2,5)=C5
FOR D1=1 TO 6
IF IsValid (3, 0, D1)=True THEN
LET Board(3,0)=D1
FOR D2=1 TO 6
IF IsValid (3, 2, D2)=True THEN
LET Board(3,2)=D2
FOR D3=1 TO 6
IF IsValid (3, 3, D3)=True THEN
LET Board(3,3)=D3
FOR D4=1 TO 6
IF IsValid (3, 4, D4)=True THEN
LET Board(3,4)=D4
FOR D5=1 TO 6
IF IsValid (3, 5, D5)=True THEN
LET Board(3,5)=D5
FOR E1=1 TO 6
IF IsValid (4, 1, E1)=True THEN
LET Board(4,1)=E1
FOR E2=1 TO 6
IF IsValid (4, 2, E2)=True THEN
LET Board(4,2)=E2
FOR E3=1 TO 6
IF IsValid (4, 3, E3)=True THEN
LET Board(4,3)=E3
FOR E4=1 TO 6
IF IsValid (4, 4, E4)=True THEN
LET Board(4,4)=E4
FOR E5=1 TO 6
IF IsValid (4, 5, E5)=True THEN
LET Board(4,5)=E5
FOR F1=1 TO 6
IF IsValid (5, 0, F1)=True THEN
LET Board(5,0)=F1
FOR F2=1 TO 6
IF IsValid (5, 1, F2)=True THEN
LET Board(5,1)=F2
FOR F3=1 TO 6
IF IsValid (5, 2, F3)=True THEN
LET Board(5,2)=F3
FOR F4=1 TO 6
IF IsValid (5, 4, F4)=True THEN
LET Board(5,4)=F4
FOR F5=1 TO 6
IF IsValid (5, 5, F5)=True THEN
LET Board(5,5)=F5
LET COUNT=COUNT+1
PRINT "解けた盤面:";COUNT
FOR i = 0 TO 5
FOR j = 0 TO 5
PRINT Board(i, j);
NEXT j
PRINT
NEXT i
IF COUNT=100 THEN STOP
LET Board(5,5)=0
END IF
NEXT F5
LET Board(5,4)=0
END IF
NEXT F4
LET Board(5,2)=0
END IF
NEXT F3
LET Board(5,1)=0
END IF
NEXT F2
LET Board(5,0)=0
END IF
NEXT F1
LET Board(4,5)=0
END IF
NEXT E5
LET Board(4,4)=0
END IF
NEXT E4
LET Board(4,3)=0
END IF
NEXT E3
LET Board(4,2)=0
END IF
NEXT E2
LET Board(4,1)=0
END IF
NEXT E1
LET Board(3,5)=0
END IF
NEXT D5
LET Board(3,4)=0
END IF
NEXT D4
LET Board(3,3)=0
END IF
NEXT D3
LET Board(3,2)=0
END IF
NEXT D2
LET Board(3,0)=0
END IF
NEXT D1
LET Board(2,5)=0
END IF
NEXT C5
LET Board(2,3)=0
END IF
NEXT C4
LET Board(2,2)=0
END IF
NEXT C3
LET Board(2,1)=0
END IF
NEXT C2
LET Board(2,0)=0
END IF
NEXT C1
LET Board(1,4)=0
END IF
NEXT B5
LET Board(1,3)=0
END IF
NEXT B4
LET Board(1,2)=0
END IF
NEXT B3
LET Board(1,1)=0
END IF
NEXT B2
LET Board(1,0)=0
END IF
NEXT B1
LET Board(0,5)=0
END IF
NEXT A4
LET Board(0,4)=0
END IF
NEXT A3
LET Board(0,3)=0
END IF
NEXT A2
LET Board(0,1)=0
END IF
NEXT A1
FUNCTION IsValid (Row,COL,Num)
!' 行と列をチェック
FOR i = 0 TO 5
IF Board(Row, i) = Num THEN
LET IsValid = False
EXIT FUNCTION
END IF
IF Board(i, Col) = Num THEN
LET IsValid = False
EXIT FUNCTION
END IF
NEXT i
LET IsValid = True
END FUNCTION
END
十進BASIC Ver.7.8.7の計画 - SHIRAISHI Kazuo
2024/12/19 (Thu) 07:19:46
JIS Full BASICの描点がオフになる条件の規定は扱いにくいだけで利点を見出しにくいものです。
https://decimalbasic.web.fc2.com/QA-plot.htm
その制限を緩和するために独自命令 SET BEAM MODE を追加しましたが,beam modeの初期値をJIS非互換の側に振ることにします。
もうひとつ,JIS規格が扱いにくいのが,TEXTが問題座標で指定され,座標系の設定によって文字が歪むという規定です。
利点もあるけれども,数学などの技術系においてラベルを描く目的には適さない規定なので,これも無視するのを初期値にします。
SET LINE WIDTHのバグ - しばっち
2024/12/15 (Sun) 08:35:53
SET LINE WIDTH文のバグです
ループ内にPLOT TEXTとPLOT LINEがあるとSET LINE WIDTH文が無効になるようです。
Lazarus版でも同様の現象を確認しました。
SET BITMAP SIZE 400,400
SET WINDOW 0,399,399,0
SET TEXT HEIGHT 50
SET TEXT COLOR 5
FOR X=0 TO 399
PLOT TEXT ,AT 100,100:"ABCDE" ! ここを注釈にすると太さ20のラインが正常に描かれる
SET LINE WIDTH 20
PLOT LINES:X,X;
NEXT X
END
Re: SET LINE WIDTHのバグ - SHIRAISHI Kazuo
2024/12/15 (Sun) 09:36:35
JIS Full BASICのPLOT LINES文にはやっかいな規定があります。
描点(BEAM)がオフになる条件がいくつか定められていて,PLOT LINES以外の図形出力文の実行時もその一つです。
独自拡張命令の SET BEAM MODE "IMMORTAL" を追加すると,この規定を無視します。
SET BITMAP SIZE 400,400
SET WINDOW 0,399,399,0
SET TEXT HEIGHT 50
SET TEXT COLOR 5
SET LINE WIDTH 20
SET BEAM MODE "IMMORTAL"
FOR X=0 TO 399
PLOT POINTS: 0,0
SET LINE WIDTH 20
PLOT TEXT ,AT 100,100:"ABCDE"
PLOT LINES:X,X;
NEXT X
END
スネークゲーム - しばっち
2024/12/15 (Sun) 08:33:59
テンキーの2,4,6,8キー又は矢印キーで緑の壁及び自身から伸びる白い壁にぶつからないように
すばやいキー操作でかわすだけのゲームです。
3秒毎に速度が増し一定時間が経つとクリアになります。
DECLARE EXTERNAL FUNCTION STICK
RANDOMIZE
DIM VEC(4)
LET XSIZE=600 ! 画像サイズ(狭くすると難しくなります)
LET YSIZE=600
LET HEIGHT=50
LET WIDTH=20 ! 外枠の幅
LET SIZE=20 ! 自身のサイズ
LET CLEARTIME=30 ! クリア時間(長くすると難しくなります)
LET INC=.5 ! 速度増加分(増やすと難しくなります)
LET DELAYTIME=1/10 ! ウェイト時間(短くすると難しくなります)
CALL GINIT(XSIZE,YSIZE)
SET TEXT JUSTIFY "CENTER" , "HALF"
SET TEXT BACKGROUND "OPAQUE"
SET TEXT HEIGHT HEIGHT
SET TEXT COLOR 7
PLOT TEXT ,AT XSIZE/2,YSIZE/2:"HIT ANY KEY"
CHARACTER INPUT A$
DO ! ゲームスタート
CLEAR
LET SPEED=2 ! 初期スピード
SET LINE WIDTH WIDTH ! 外枠の幅
CALL BOX(0,HEIGHT+WIDTH/2,XSIZE-1,YSIZE-1,4) ! 外枠
LET X=XSIZE/2+RND*XSIZE/3*COS(2*RND*PI) ! 初期位置
LET Y=YSIZE/2+RND*YSIZE/3*SIN(2*RND*PI)
LET PX=INT(X/(XSIZE/3)) ! 3*3分割
LET PY=INT(Y/(YSIZE/3))
LET N=PX+3*PY ! エリア割り振り
SELECT CASE N
CASE 0
LET VEC(1)=6 ! 向き指定
LET VEC(2)=2
LET SS=VEC(INT(RND*2+1)) ! 初期向き
CASE 1
LET VEC(1)=4
LET VEC(2)=6
LET VEC(3)=2
LET SS=VEC(INT(RND*3+1))
CASE 2
LET VEC(1)=2
LET VEC(2)=4
LET SS=VEC(INT(RND*2+1))
CASE 3
LET VEC(1)=8
LET VEC(2)=6
LET VEC(3)=2
LET SS=VEC(INT(RND*3+1))
CASE 4
LET VEC(1)=2
LET VEC(2)=4
LET VEC(3)=6
LET VEC(4)=8
LET SS=VEC(INT(RND*4+1))
CASE 5
LET VEC(1)=2
LET VEC(2)=4
LET VEC(3)=8
LET SS=VEC(INT(RND*3+1))
CASE 6
LET VEC(1)=6
LET VEC(2)=8
LET SS=VEC(INT(RND*2+1))
CASE 7
LET VEC(1)=4
LET VEC(2)=6
LET VEC(3)=8
LET SS=VEC(INT(RND*3+1))
CASE 8
LET VEC(1)=4
LET VEC(2)=8
LET SS=VEC(INT(RND*2+1))
END SELECT
LET TI=INT(TIME) ! タイマーセット
LET T=TI
DO
SET TEXT HEIGHT HEIGHT-WIDTH
SET TEXT COLOR 7
SET TEXT JUSTIFY "CENTER" , "TOP"
LET SCORE=SCORE+SPEED
PLOT TEXT ,AT XSIZE/2,0:"スコア:"&STR$(INT(SCORE/10))&" 残り:"&STR$(CLEARTIME-INT(TIME-T))&"秒 "
LET S=STICK ! キー操作
IF S=0 THEN
LET S=SS
ELSE
LET SS=S
END IF
SELECT CASE S
CASE 2
LET YS=SPEED
LET XS=0
LET COL=GETPOINT(X-SIZE/2,Y+SIZE/2+YS)+GETPOINT(X+SIZE/2,Y+SIZE/2+YS) ! 当たり判定
CASE 4
LET XS=-SPEED
LET YS=0
LET COL=GETPOINT(X-SIZE/2+XS,Y-SIZE/2)+GETPOINT(X-SIZE/2+XS,Y+SIZE/2)
CASE 6
LET XS=SPEED
LET YS=0
LET COL=GETPOINT(X+SIZE/2+XS,Y-SIZE/2)+GETPOINT(X+SIZE/2+XS,Y+SIZE/2)
CASE 8
LET XS=0
LET YS=-SPEED
LET COL=GETPOINT(X-SIZE/2,Y-SIZE/2+YS)+GETPOINT(X+SIZE/2,Y-SIZE/2+YS)
CASE ELSE
END SELECT
LET XX=X+XS
LET YY=Y+YS
! SET LINE COLOR SPEED
! SET LINE WIDTH SIZE
! PLOT LINES:XX,YY; ! バグ
CALL BOXFULL(MIN(X,XX)-SIZE/2,MIN(Y,YY)-SIZE/2,MAX(X,XX)+SIZE/2,MAX(Y,YY)+SIZE/2,7) ! 自身の表示
! CALL BOXFULL(MIN(X,XX)-SIZE/2,MIN(Y,YY)-SIZE/2,MAX(X,XX)+SIZE/2,MAX(Y,YY)+SIZE/2,SPEED)
LET X=XX
LET Y=YY
IF COL<>0 OR X<0 OR X>XSIZE OR Y<0 OR Y>YSIZE THEN ! 壁にぶつかったら
SET TEXT COLOR 2
SET TEXT HEIGHT HEIGHT*1.5
SET TEXT JUSTIFY "CENTER" , "HALF"
PLOT TEXT ,AT XSIZE/2,YSIZE/2:"GAME OVER!!"
STOP
END IF
IF TIME-T>=CLEARTIME THEN ! 面クリア
SET TEXT COLOR 6
SET TEXT HEIGHT HEIGHT*1.5
SET TEXT JUSTIFY "CENTER" , "HALF"
PLOT TEXT ,AT XSIZE/2,YSIZE/2:"GAME CLEAR"
LET CLEARTIME=CLEARTIME+5 ! クリア毎に5秒ずつ延長
WAIT DELAY 2 ! 待機
EXIT DO
END IF
IF TIME-TI>=3 THEN ! 加速 3秒毎
LET SPEED=SPEED+INC ! 増分
LET INC=INC+.5
LET TI=INT(TIME)
END IF
WAIT DELAY DELAYTIME ! ウェイト
LOOP
LOOP
END
EXTERNAL SUB BOX(XS,YS,XE,YE,C)
SET LINE COLOR C
PLOT LINES:XS,YS;XE,YS
PLOT LINES:XE,YS;XE,YE
PLOT LINES:XE,YE;XS,YE
PLOT LINES:XS,YE;XS,YS
END SUB
EXTERNAL SUB BOXFULL(X1,Y1,X2,Y2,C)
SET AREA COLOR C
PLOT AREA:X1,Y1;X2,Y1;X2,Y2;X1,Y2;X1,Y1
END SUB
EXTERNAL SUB GINIT(XSIZE,YSIZE)
SET BITMAP SIZE XSIZE,YSIZE
SET WINDOW 0,XSIZE-1,YSIZE-1,0
SET POINT STYLE 1
SET COLOR MODE "REGULAR"
FOR I=0 TO 7
SET COLOR MIX(I) BITAND(I,2)/2,BITAND(I,4)/4,BITAND(I,1)
NEXT I
CLEAR
END SUB
EXTERNAL FUNCTION GETPOINT(X,Y)
ASK PIXEL VALUE(X,Y) C
LET GETPOINT=C
END FUNCTION
EXTERNAL FUNCTION STICK
LET STICK=0
FOR I=97 TO 105
IF GETKEYSTATE(I)<0 THEN
LET STICK=I-96
EXIT FUNCTION
END IF
NEXT I
FOR I=49 TO 57
IF GETKEYSTATE(I)<0 THEN
LET STICK=I-48
EXIT FUNCTION
END IF
NEXT I
IF GETKEYSTATE(37)<0 THEN LET STICK=4
IF GETKEYSTATE(38)<0 THEN LET STICK=8
IF GETKEYSTATE(39)<0 THEN LET STICK=6
IF GETKEYSTATE(40)<0 THEN LET STICK=2
END FUNCTION
シミュラクラ現象 - しばっち
2024/11/17 (Sun) 08:08:05
https://ja.wikipedia.org/wiki/シミュラクラ現象
https://ja.wikipedia.org/wiki/パレイドリア
下記プログラムでは大きな丸(円・楕円)の中に丸(円・楕円)を3つ描いただけのものです(サンプル画像)
もし、これが人の顔のように見えたのならシミュラクラ現象(パレイドリア現象)による錯覚が起きた
といえるのではないでしょうか。
どんな時に錯覚(シミュラクラ現象、パレイドリア現象)が起きるのか検証してみるのも
おもしろいかもしれません。
SET WINDOW -.1,1.1,-.1,1.1
LOCATE VALUE NOWAIT(1) ,RANGE -.5 TO .5,AT 0:MOVEX1
LOCATE VALUE NOWAIT(2) ,RANGE -.5 TO .5,AT 0:MOVEY1
LOCATE VALUE NOWAIT(3) ,RANGE .1 TO 1,AT .45:SCALEX1
LOCATE VALUE NOWAIT(4) ,RANGE .1 TO 1,AT .57:SCALEY1
LOCATE VALUE NOWAIT(5) ,RANGE 3 TO 120,AT 3:N1
LOCATE VALUE NOWAIT(6) ,RANGE 0 TO 360,AT 0:ANG1
LOCATE VALUE NOWAIT(7) ,RANGE 0 TO .5,AT .21:MOVEX2
LOCATE VALUE NOWAIT(8) ,RANGE -.5 TO .5,AT 0:MOVEY2
LOCATE VALUE NOWAIT(9) ,RANGE .1 TO .5,AT .11:SCALEX2
LOCATE VALUE NOWAIT(10) ,RANGE .1 TO .5,AT .1:SCALEY2
LOCATE VALUE NOWAIT(11) ,RANGE 3 TO 120,AT 3:N2
LOCATE VALUE NOWAIT(12) ,RANGE 0 TO 360,AT 0:ANG2
LOCATE VALUE NOWAIT(13) ,RANGE -.5 TO .5,AT 0:MOVEX3
LOCATE VALUE NOWAIT(14) ,RANGE -.5 TO .5,AT 0:MOVEY3
LOCATE VALUE NOWAIT(15) ,RANGE .1 TO .5,AT .18:SCALEX3
LOCATE VALUE NOWAIT(16) ,RANGE .1 TO .5,AT .1:SCALEY3
LOCATE VALUE NOWAIT(17) ,RANGE 3 TO 120,AT 3:N3
LOCATE VALUE NOWAIT(18) ,RANGE 0 TO 360,AT 0:ANG3
DO
LOCATE VALUE NOWAIT(1):MOVEX1
LOCATE VALUE NOWAIT(2):MOVEY1
LOCATE VALUE NOWAIT(3):SCALEX1
LOCATE VALUE NOWAIT(4):SCALEY1
LOCATE VALUE NOWAIT(5):N1
LOCATE VALUE NOWAIT(6):ANG1
LET R1=INT(360/INT(N1))
LOCATE VALUE NOWAIT(7):MOVEX2
LOCATE VALUE NOWAIT(8):MOVEY2
LOCATE VALUE NOWAIT(9):SCALEX2
LOCATE VALUE NOWAIT(10):SCALEY2
LOCATE VALUE NOWAIT(11):N2
LOCATE VALUE NOWAIT(12):ANG2
LET R2=INT(360/INT(N2))
LOCATE VALUE NOWAIT(13):MOVEX3
LOCATE VALUE NOWAIT(14):MOVEY3
LOCATE VALUE NOWAIT(15):SCALEX3
LOCATE VALUE NOWAIT(16):SCALEY3
LOCATE VALUE NOWAIT(17):N3
LOCATE VALUE NOWAIT(18):ANG3
LET R3=INT(360/INT(N3))
DRAW POLY(R1) WITH SCALE(SCALEX1,SCALEY1)*ROTATE(ANG1)*SHIFT(.5+MOVEX1,.5+MOVEY1)
DRAW POLY(R2) WITH SCALE(SCALEX2,SCALEY2)*ROTATE(ANG2)*SHIFT(.5-MOVEX2,.7+MOVEY2)
DRAW POLY(R2) WITH SCALE(SCALEX2,SCALEY2)*ROTATE(ANG2)*SHIFT(.5+MOVEX2,.7+MOVEY2)
DRAW POLY(R3) WITH SCALE(SCALEX3,SCALEY3)*ROTATE(ANG3)*SHIFT(.5+MOVEX3,.2+MOVEY3)
SET DRAW MODE EXPLICIT
WAIT DELAY .2
SET DRAW MODE HIDDEN
CLEAR
LOOP
END
EXTERNAL PICTURE POLY(N)
OPTION ANGLE DEGREES
FOR T=0 TO 360+N STEP 360/N
PLOT LINES: COS(T),SIN(T);
NEXT T
PLOT LINES
END PICTURE
Collatz problem 6*n + 4.と奇数列の関係 - Tarosa
2024/11/05 (Tue) 09:30:32
!!Collatz problem Displaying 1-2 of 2 results found.
!A016957 a(n) = 6*n + 4.
!6*n + 4.と奇数列の関係
LET nn=0
FOR n=1 TO 100
LET s=2*n
LET s1=6*nn+4
IF MOD((s-1),3)=0 THEN
PRINT s;(s-1)/3;s1
LET nn=nn+1
END IF
NEXT n
END
!2*nならば 2n/2n=1 は必ず1になる。つまり、奇数列は1になる。この照明は?
Re: Collatz problem 6*n + 4.と奇数列の関係 - Tarosa
2024/11/05 (Tue) 09:34:52
計算結果出力
4 1 4
10 3 10
16 5 16
22 7 22
28 9 28
34 11 34
40 13 40
46 15 46
52 17 52
58 19 58
64 21 64
70 23 70
76 25 76
82 27 82
88 29 88
94 31 94
100 33 100
2n の IF MOD((s-1),3)=0 は 6*n + 4
Re: Collatz problem 6*n + 4.と奇数列の関係 - Tarosa
2024/11/05 (Tue) 17:50:10
!Collatz problem 3
OPTION ARITHMETIC NATIVE
!OPTION ARITHMETIC DECIMAL_HIGH
LET t0=TIME
LET cc=1
LET c1=0
LET odd=0
LET eve=0
FOR n= 0 TO 1E8
LET a1=3*3*n+2
IF MOD(a1,2)=0 THEN
LET b1=a1/2
ELSE
LET b1=a1*3+1
END IF
!PRINT a1; b1 !1
IF MOD(b1,2)=0 THEN
LET eve=eve+1
ELSE
LET odd=odd+1
END IF
LET a2=3*3*n+4
IF MOD(a2,2)=0 THEN
LET b2=a2/2
ELSE
LET b2=a2*3+1
END IF
!PRINT a2;b2 !2
IF MOD(b2,2)=0 THEN
LET eve=eve+1
ELSE
LET odd=odd+1
END IF
IF MOD(n,2)=0 THEN
LET a31=3*c1+1
IF MOD(a31,2)=0 THEN
LET b31=a31/2
ELSE
LET b31=a31*3+1
END IF
!PRINT a31;b31 !3-1
LET c1=c1+1
IF MOD(b31,2)=0 THEN
LET eve=eve+1
ELSE
LET odd=odd+1
END IF
END IF
IF MOD(n,2)=1 THEN
LET a32=18*cc-2
IF MOD(a32,2)=0 THEN
LET b32=a32/2
ELSE
LET b32=a32*3+1
END IF
!PRINT a32;b32 !3-2
LET cc=cc+1
IF MOD(b32,2)=0 THEN
LET eve=eve+1
ELSE
LET odd=odd+1
END IF
END IF
LET a4=3*3*6*n+52
IF MOD(a4,2)=0 THEN
LET b4=a4/2
ELSE
LET b4=a4*3+1
END IF
!PRINT a4;b4 !4
IF MOD(b4,2)=0 THEN
LET eve=eve+1
ELSE
LET odd=odd+1
END IF
NEXT n
PRINT
PRINT "eve";eve
PRINT "odd";odd
LET TM=TIME-t0
PRINT USING"####." & REPEAT$("#",2):TM;
PRINT "秒"
END
6n+4は全て偶数
even number/2 or odd number*3+1
(6n+4)/2 ~ 3n+2 更に 3n+1 と 18n+16 その後の数列は
計算結果出力
FOR n= 0 TO 100
eve 266
odd 138
FOR n= 0 TO 1000
eve 2628
odd 1376
FOR n= 0 TO 1E4
eve 26253
odd 13751
FOR n= 0 TO 1E5
eve 262503
odd 137501
FOR n= 0 TO 1E6
eve 2625003
odd 1375001
FOR n= 0 TO 1E7
eve 26250003
odd 13750001
5.24秒
eve 26250003
odd 13750001
154.43秒 1000桁モード
FOR n= 0 TO 1E8
eve 262500003
odd 137500001
51.54秒
FOR n= 0 TO 1E9
eve 2625000003
odd 1375000001
eve 2625000003
odd 1375000001
39.87秒
FOR n= 0 TO 1E10
eve 26250000003
odd 13750000001
399.59秒
規則正しく偶数が多い。事は照明可能か?
Re: Collatz problem 6*n + 4.と奇数列の関係 - Tarosa
2024/11/10 (Sun) 21:23:53
!Collatz problem 3
OPTION ARITHMETIC NATIVE
LET t0=TIME
LET cc=1
LET c1=0
LET eve=0
LET odd=0
FOR n= 0 TO 1E5
LET a1=3*3*n+2
IF MOD (a1,2)=0 THEN
LET eve=eve+1
ELSE
LET odd=odd+1
END IF
!PRINT !1
LET a2=3*3*n+4
IF MOD (a2,2)=0 THEN
LET eve=eve+1
ELSE
LET odd=odd+1
END IF
!PRINT !2
IF MOD(n,2)=0 THEN
LET a31=3*c1+1
IF MOD (a31,2)=0 THEN
LET eve=eve+1
ELSE
LET odd=odd+1
END IF
!PRINT !31
LET c1=c1+1
END IF
IF MOD(n,2)=1 THEN
LET a32=18*cc-2
IF MOD (a32,2)=0 THEN
LET eve=eve+1
ELSE
LET odd=odd+1
END IF
!PRINT !32
LET cc=cc+1
END IF
LET a4=3*3*6*n+52
IF MOD (a4,2)=0 THEN
LET eve=eve+1
ELSE
LET odd=odd+1
END IF
!PRINT !4
NEXT n
PRINT "eve=";eve
PRINT "odd=";odd
LET TM=TIME-t0
PRINT USING"####." & REPEAT$("#",2):TM;
PRINT "秒"
END
!Collatz problem
FOR n= 0 TO 100
eve= 278
odd= 126
FOR n= 0 TO 1000
eve= 2753
odd= 1251
FOR n= 0 TO 10000
eve= 27503
odd= 12501
FOR n= 0 TO 1E5
eve= 275003
odd= 125001
FOR n= 0 TO 1E6
eve= 2750003
odd= 1250001
FOR n= 0 TO 1E7
eve= 27500003
odd= 12500001
FOR n= 0 TO 1E8
eve= 275000003
odd= 125000001
FOR n= 0 TO 1E9
eve= 2750000003
odd= 1250000001
FOR n= 0 TO 1E10
eve= 27500000003
odd= 12500000001
348.82秒
FOR n= 0 TO 1E11
eve= 275000000003
odd= 125000000001
3458.11秒
(((6n+4)/2)even/2 or odd*3+1)even/2 or odd*3+1
2,4,1,52,11,13,16,106,20,22,4,160,29,31,34,214,38,
偶数が多い。2の倍数の次に3の倍数が多いのは自明
不思議なのは・・・
6n-1,6n+1と五角数の関係 - Tarosa
2024/10/29 (Tue) 21:56:33
!6n-1,6n+1と五角数の関係
!A001318 Generalized pentagonal numbers: m*(3*m - 1)/2, m = 0, +-1, +-2, +-3, ....
OPTION ARITHMETIC NATIVE
FOR n=1 TO 1000/3
LET p=n*(3*n-1)/2
LET k=((6*n-1)^2-1)/24
LET p1=n*(3*n+1)/2
LET k1=((6*n+1)^2-1)/24
PRINT p;k
PRINT p1;k1
NEXT n
END
計算結果出力
1 1
2 2
5 5
7 7
12 12
15 15
22 22
26 26
35 35
40 40
51 51
57 57
70 70
77 77
92 92
100 100
6n+1 の数列を眺めていたら・・・
5以上のすべての素数のPn^2 が・・・
Re: 6n-1,6n+1と五角数の関係 - Tarosa
2024/10/29 (Tue) 22:03:58
!6n-1,6n+1
OPTION ARITHMETIC NATIVE
FOR n=1 TO 10000/6
LET p=SQR((n*(3*n-1)/2)*24+1)
!LET p=SQR(12*n*(3*n-1)+ 1)
LET k=6*n-1
LET p1=SQR((n*(3*n+1)/2)*24+1)
!LET p1=SQR(12*n*(3*n+1)+ 1)
LET k1=6*n+1
PRINT p;k
PRINT p1;k1
NEXT n
END
計算結果出力
5 5
7 7
11 11
13 13
17 17
19 19
23 23
25 25
29 29
31 31
35 35
37 37
41 41
43 43
47 47
49 49
53 53
55 55
59 59
確率的素数と5角数の関係
Re: 6n-1,6n+1と五角数の関係 - Tarosa
2024/10/29 (Tue) 22:08:50
!https://oeis.org/A001318
!A001318 Generalized pentagonal numbers: m*(3*m - 1)/2, m = 0, +-1, +-2, +-3, ....
OPTION ARITHMETIC NATIVE
LET t0=TIME
LET k6=1299709 !31607 !10億,31607 1億,9973
LET k2=100000 !3401 !10億,3401 1億,1229
!エラトステネスの篩
DIM P(k6)
DIM A(k2) !素数
MAT P=ZER
MAT A=ZER
LET A(1)=2
LET H1=1
FOR I=3 TO SQR(k6) STEP 2
IF P(I)=0 THEN
FOR J=I*I TO k6 STEP I
LET P(J)=1
NEXT J
END IF
NEXT I
FOR I=3 TO k6 STEP 2
IF P(I)=0 THEN
LET H1=H1+1
LET A(H1)=I
END IF
NEXT I
LET Z=10000
DIM Pn(z)
DIM Pm(z)
MAT Pn = ZER
LET cc=1
FOR n=1 TO z/2
LET pp=n*(3*n-1)/2
LET Pn(cc)=pp
LET cc=cc+1
LET p1=n*(3*n+1)/2
LET Pn(cc)=p1
LET cc=cc+1
NEXT n
LET S=0
FOR n=1 TO z
LET Pm(n)=SQR(Pn(n)*24+1)
!PRINT
next n
LET c1=1
LET cc=3
FOR n=1 TO z
LET DD=Pm(n)
FOR nn=c1 TO z
IF DD=A(nn) THEN
PRINT cc;A(nn)
LET cc=cc+1
LET c1=c1+1
EXIT FOR
END IF
NEXT nn
NEXT n
LET TM=TIME-t0
PRINT USING"####." & REPEAT$("#",2):TM;
PRINT "秒"
END
計算結果出力
3 5
4 7
5 11
6 13
7 17
8 19
9 23
10 29
11 31
12 37
13 41
14 43
15 47
16 53
17 59
18 61
19 67
20 71
21 73
22 79
23 83
24 89
25 97
26 101
素数の個数と素数
双2次フィルタ - しばっち
2024/10/13 (Sun) 08:23:02
双2次フィルタ
双2次フィルタ(IIRフィルタ)でフィルタ処理してみました。
https://ufcpp.net/study/sp/digital_filter/biquad/
https://www.wizard-notes.com/entry/music-analysis/biquad-filter-frequency-responses
https://www.utsbox.com/?page_id=523
https://www.utsbox.com/?page_id=728
https://qiita.com/Micochan/items/6be0034a9f75bb0706cd
https://qiita.com/fukuroder/items/e1cd551b7492020da992
https://nettyukobo.com/bilinear_transform/
https://qiita.com/fukuroder/items/e1cd551b7492020da992
https://hp.vector.co.jp/authors/VA009014/jp/my_sticker_file_01.html
2進モードで実行してください。
LET M=8
LET N=2^M
LET SAMPLINGFREQ=44100 ! サンプリング周波数
LET FREQ=1000
LET Q=1/SQR(2) ! Q>0
LET BW=1 ! BW>0
LET GAIN=3
DIM IN(N),OUT(N)
LET FILTER=0
SET WINDOW 1,N,-1.5,1.5
DRAW GRID(N/8,.3)
FOR I=1 TO N
LET IN(I)=SIN(600/SAMPLINGFREQ*I*2*PI)+.2*SIN(2000/SAMPLINGFREQ*I*2*PI) ! 600Hzと2000Hzの合成波形
PLOT LINES:I,IN(I);
NEXT I
CALL BIQUAD(IN,FILTER,N,SAMPLINGFREQ,FREQ,Q,BW,GAIN,OUT) ! 双2次フィルタ
PLOT LINES
PAUSE
CLEAR
DRAW GRID(N/8,.3)
FOR I=1 TO N
PLOT LINES:I,OUT(I); ! 結果表示
NEXT I
END
SUB BIQUAD(IN(),FILTER,NUM,SAMPLINGFREQ,FREQ,Q,BW,GAIN,OUT())
SELECT CASE FILTER
CASE 0 ! LPF
LET OMEGA=2*PI*FREQ/SAMPLINGFREQ
LET ALPHA=SIN(OMEGA)/(2*Q)
LET A0=1+ALPHA
LET A1=-2*COS(OMEGA)
LET A2=1-ALPHA
LET B0=(1-COS(OMEGA))/2
LET B1=1-COS(OMEGA)
LET B2=(1-COS(OMEGA))/2
CASE 1 ! HPF
LET OMEGA=2*PI*FREQ/SAMPLINGFREQ
LET ALPHA=SIN(OMEGA)/(2*Q)
LET A0=1+ALPHA
LET A1=-2*COS(OMEGA)
LET A2=1-ALPHA
LET B0=(1+COS(OMEGA))/2
LET B1=-(1+COS(OMEGA))
LET B2=(1+COS(OMEGA))/2
CASE 2 ! BPF
LET OMEGA=2*PI*FREQ/SAMPLINGFREQ
LET ALPHA=SIN(OMEGA)*SINH(LOG(2)/2*BW*OMEGA/SIN(OMEGA))
LET A0=1+ALPHA
LET A1=-2*COS(OMEGA)
LET A2=1-ALPHA
LET B0=ALPHA
LET B1=0
LET B2=-ALPHA
CASE 3 ! NOTCH
LET OMEGA=2*PI*FREQ/SAMPLINGFREQ
LET ALPHA=SIN(OMEGA)*SINH(LOG(2)/2*BW*OMEGA/SIN(OMEGA))
LET A0=1+ALPHA
LET A1=-2*COS(OMEGA)
LET A2=1-ALPHA
LET B0=1
LET B1=-2*COS(OMEGA)
LET B2=1
CASE 4 ! LOWSHELF
LET OMEGA=2*PI*FREQ/SAMPLINGFREQ
LET ALPHA=SIN(OMEGA)/(2*Q)
LET A=10^(GAIN/40)
LET BETA=SQR(A)/Q
LET A0=(A+1)+(A-1)*COS(OMEGA)+BETA*SIN(OMEGA)
LET A1=-2*((A-1)+(A+1)*COS(OMEGA))
LET A2=(A+1)+(A-1)*COS(OMEGA)-BETA*SIN(OMEGA)
LET B0=A*((A+1)-(A-1)*COS(OMEGA)+BETA*SIN(OMEGA))
LET B1=2*A*((A-1)-(A+1)*COS(OMEGA))
LET B2=A*((A+1)-(A-1)*COS(OMEGA)-BETA*SIN(OMEGA))
CASE 5 ! HIGHSHELF
LET OMEGA=2*PI*FREQ/SAMPLINGFREQ
LET ALPHA=SIN(OMEGA)/(2*Q)
LET A=10^(GAIN/40)
LET BETA=SQR(A)/Q
LET A0=(A+1)-(A-1)*COS(OMEGA)+BETA*SIN(OMEGA)
LET A1=2*((A-1)-(A+1)*COS(OMEGA))
LET A2=(A+1)-(A-1)*COS(OMEGA)-BETA*SIN(OMEGA)
LET B0=A*((A+1)+(A-1)*COS(OMEGA)+BETA*SIN(OMEGA))
LET B1=-2*A*((A-1)+(A+1)*COS(OMEGA))
LET B2=A*((A+1)+(A-1)*COS(OMEGA)-BETA*SIN(OMEGA))
CASE 6 ! PEAKING
LET OMEGA=2*PI*FREQ/SAMPLINGFREQ
LET ALPHA=SIN(OMEGA)*SINH(LOG(2)/2*BW*OMEGA/SIN(OMEGA))
LET A=10^(GAIN/40)
LET A0=1+ALPHA/A
LET A1=-2*COS(OMEGA)
LET A2=1-ALPHA/A
LET B0=1+ALPHA*A
LET B1=-2*COS(OMEGA)
LET B2=1-ALPHA*A
CASE 7 ! ALL PASS
LET OMEGA=2*PI*FREQ/SAMPLINGFREQ
LET ALPHA=SIN(OMEGA)/(2*Q)
LET A0=1+ALPHA
LET A1=-2*COS(OMEGA)
LET A2=1-ALPHA
LET B0=1-ALPHA
LET B1=-2*COS(OMEGA)
LET B2=1+ALPHA
END SELECT
FOR I=1 TO NUM
LET OUT(I)=B0/A0*IN(I)+B1/A0*IN1+B2/A0*IN2-A1/A0*OUT1-A2/A0*OUT2
LET IN2=IN1
LET IN1=IN(I)
LET OUT2=OUT1
LET OUT1=OUT(I)
NEXT
END SUB
--------------------------------------------------------------------------------------------------
wavファイルに書き出して聞き比べられるようにしてみました。
※スピーカーのボリュームに気を付けてください
LET SAMPLINGFREQ=44100 ! サンプリング周波数
LET N=SAMPLINGFREQ*3 ! 再生時間3秒
DIM IN(N),OUT(N)
LET VOL=.5
FOR I=1 TO N
LET IN(I)=.6*SIN(800/SAMPLINGFREQ*I*2*PI)+.3*SIN(4000/SAMPLINGFREQ*I*2*PI)+.1*SIN(12000/SAMPLINGFREQ*I*2*PI) ! 800Hz 4000Hz 12000Hzの合成波形
LET IN(I)=IN(I)*VOL
NEXT I
CALL WRITEWAV("元音.wav",N,1,SAMPLINGFREQ,16,IN)
LET FILTER=0
!INPUT PROMPT "LPF(0) HPF(1) BPF(2) NOTCH(3) LOWSHELF(4) HIGHSHELF(5) PEAKING(6) ALL PASS(7) ":FILTER
CALL BIQUAD(IN,FILTER,N,SAMPLINGFREQ,1000,1/SQR(2),1,3,OUT)
CALL WRITEWAV("処理後.wav",N,SAMPLINGFREQ,16,OUT)
END
以下略
--------------------------------------------------------------------------------------------------
音声合成(フォルマント合成)
https://ja.wikipedia.org/wiki/フォルマント
https://smartsoundlab.com/2019/01/000047.html
https://moge32.blogspot.com/2012/08/3c.html
https://qiita.com/MuAuan/items/7958ca655a7f143deb29
https://nettyukobo.com/ieaou/
https://smartsoundlab.com/2019/01/000047.html
フィルタ処理によって「あいうえお」を発声します。
OPTION BASE 0
LET SAMPLINGFREQ = 8000
LET NUM=SAMPLINGFREQ
DIM A(0 TO 3), B(0 TO 3)
DIM PCM0(NUM),PCM1(NUM),S(NUM),OUT(NUM*5)
FOR P=0 TO 4
READ F1,F2,F3,F4 ! フォルマント周波数
DATA 800,1200,2500,3500 ! あ
DATA 300,2300,2900,3500 ! い
DATA 300,1200,2500,3500 ! う
DATA 500,1900,2500,3500 ! え
DATA 500,800,2500,3500 ! お
LET B1 = 100
LET B2 = 100
LET B3 = 100
LET B4 = 100
MAT PCM0=ZER
MAT PCM1=ZER
FOR I=1 TO NUM
FOR J=1 TO 32
LET PCM0(I)=PCM0(I)+SIN(125*J*I*2*PI/SAMPLINGFREQ)/32
NEXT J
NEXT I
MAT S=ZER
CALL IIR_RESONATOR(F1 / SAMPLINGFREQ, F1 / B1, A, B)
CALL IIR_FILTERING(PCM0, S, NUM,A, B)
FOR N = 1 TO NUM
LET PCM1(N) = PCM1(N)+S(N)
NEXT N
MAT S=ZER
CALL IIR_RESONATOR(F2 / SAMPLINGFREQ, F2 / B2, A, B)
CALL IIR_FILTERING(PCM0, S, NUM,A, B)
FOR N = 1 TO NUM
LET PCM1(N) =PCM1(N)+ S(N)
NEXT N
MAT S=ZER
CALL IIR_RESONATOR(F3 / SAMPLINGFREQ, F3 / B3, A, B)
CALL IIR_FILTERING(PCM0, S, NUM,A, B)
FOR N = 1 TO NUM
LET PCM1(N) =PCM1(N)+S(N)
NEXT N
MAT S=ZER
CALL IIR_RESONATOR(F4 / SAMPLINGFREQ, F4 / B4, A, B)
CALL IIR_FILTERING(PCM0, S, NUM,A, B)
FOR N = 1 TO NUM
LET PCM1(N) =PCM1(N)+ S(N)
NEXT N
MAT S=ZER
LET S(1) = PCM1(1)
FOR N = 2 TO NUM
LET S(N) = 0.98 * S(N - 1) + PCM1(N)
NEXT N
FOR N = 1 TO NUM
LET PCM1(N)= S(N)
NEXT N
FOR N = 1 TO NUM * 0.01
LET PCM1(N) =PCM1(N)*N / (SAMPLINGFREQ * 0.01)
LET PCM1(NUM - N + 1)=PCM1(NUM-N+1) *N / (SAMPLINGFREQ * 0.01)
NEXT N
FOR I=1 TO NUM
LET OUT(I+NUM*P)=PCM1(I)
NEXT I
NEXT P
CALL WRITEWAV("あいうえお.wav",NUM*5,SAMPLINGFREQ,16,OUT)
END
EXTERNAL SUB IIR_RESONATOR(FC, Q, A(), B())
LET FC = TAN(PI * FC) / (2.0 * PI)
LET A(0) = 1.0 + 2.0 * PI * FC / Q+ 4.0 * PI * PI * FC * FC
LET A(1) = (8.0 * PI * PI * FC * FC - 2.0)/ A(0)
LET A(2) = (1.0 - 2.0 * PI * FC / Q+ 4.0 * PI * PI * FC * FC) / A(0)
LET B(0) = 2.0 * PI * FC / Q / A(0)
LET B(1) = 0.0
LET B(2) = -2.0 * PI * FC / Q / A(0)
LET A(0) = 1.0
END SUB
EXTERNAL SUB IIR_FILTERING(X(), Y(), L, A(), B())
FOR N = 0 TO L-1
FOR M = 0 TO 2
IF N - M >= 0 THEN
LET Y(N)=Y(N) + B(M) * X(N - M)
END IF
NEXT M
FOR M = 1 TO 2
IF N - M >= 0 THEN
LET Y(N)=Y(N) -A(M) * Y(N - M)
END IF
NEXT M
NEXT N
END SUB
以下略
--------------------------------------------------------------------------------------------------
「あ」(フォルマント合成)
https://qiita.com/rild/items/339c5c36f4c1ad8d4325
LET SAMPLINGFREQ=44100
LET PLAYTIME=1
LET NUM=SAMPLINGFREQ*PLAYTIME
DIM LIN(NUM)
FOR I=1 TO NUM
LET S=.19*SIN(2*PI*I*1040/SAMPLINGFREQ)
LET S=S+.09*SIN(2*PI*I*520/SAMPLINGFREQ)
LET S=S+.08*SIN(2*PI*I*780/SAMPLINGFREQ)
LET S=S+.08*SIN(2*PI*I*1300/SAMPLINGFREQ)
LET S=S+.07*SIN(2*PI*I*260/SAMPLINGFREQ)
LET S=S+.07*SIN(2*PI*I*1560/SAMPLINGFREQ)
LET LIN(I)=S
NEXT I
SET WINDOW 0,NUM/50,-1,1
DRAW GRID(NUM/500,.2)
FOR I=1 TO NUM/50
PLOT LINES:I,LIN(I);
NEXT I
CALL WRITEWAV("あ.wav",NUM,SAMPLINGFREQ,16,LIN)
END
以下略
なお、今回の大量書き込み(300KB超え)につきましてはご容赦くださいますようお願いします。
FIRフィルタ - しばっち
2024/10/13 (Sun) 08:14:44
FIRフィルタ
FIRフィルタによるフィルタ処理
https://ja.wikipedia.org/wiki/有限インパルス応答
http://marchan.e5.valueserver.jp/cabin/comp/jbox/arc300/doc3020.html
https://nettyukobo.com/window_function_method/
https://ryukau.github.io/filter_notes/basic_fir/basic_fir.html
まずは画像処理でぼかし処理に使用される移動平均でローパスフィルタ作ってみた。
フィルタ適用後波形が変化していることを確認してください。
2進モードで実行してください。
LET TAP=5 ! 次数
LET SAMPLINGFREQ=2000 ! サンプリング周波数
LET N=SAMPLINGFREQ
DIM IN(N),OUT(N)
FOR I=1 TO N
LET IN(I)=SIN(30*I/SAMPLINGFREQ*2*PI)*.8+SIN(800*I/SAMPLINGFREQ*2*PI)*.2
NEXT I
SET WINDOW 1,N/10,-1.5,1.5
DRAW GRID(N/20,.3)
FOR I=1 TO N/10
PLOT LINES:I,IN(I);
NEXT I
PLOT LINES
CALL FIR(IN,N,TAP,OUT)
SET LINE COLOR "RED"
FOR I=1 TO N/10
PLOT LINES:I,OUT(I);
NEXT I
END
EXTERNAL SUB FIR(IN(),N,TAPSIZE,OUT())
FOR J=1 TO N
LET S=0
FOR I=0 TO TAPSIZE-1
IF I+J<=N THEN LET S=S+IN(I+J)
NEXT I
LET OUT(J)=S/TAPSIZE
NEXT J
END SUB
-------------------------------------------------------------------------------
フィルタ係数をFFTするとフィルタ特性が分かります。
横軸が周波数、縦軸がdb(デシベル)です。
https://ja.wikipedia.org/wiki/デシベル
LET M=8
LET SAMPLINGFREQ=44100
DIM RR(2^M),II(2^M)
FOR N=2 TO 15
MAT RR=ZER
MAT II=ZER
FOR I=1 TO N
LET RR(I)=1/N
NEXT I
CALL FFT(M,RR,II,1)
CLEAR
SET WINDOW -1000,SAMPLINGFREQ/2,-80,0
DRAW GRID(SAMPLINGFREQ/10,10)
LET LL=SAMPLINGFREQ/2^M
FOR I=1 TO 2^M/2
IF RR(I)=0 AND II(I)=0 THEN
PLOT LINES:I*LL,-80;
ELSE
PLOT LINES:I*LL, 10*LOG10(RR(I)^2+II(I)^2);
END IF
NEXT I
PLOT LINES
WAIT DELAY 1
NEXT N
END
以下略
-------------------------------------------------------------------------------
ガウシアンによるFIRフィルタ
https://ja.wikipedia.org/wiki/ガウス関数
LET M=8
LET SAMPLINGFREQ=44100
DIM RR(2^M),II(2^M)
FOR N=2 TO 15
MAT RR=ZER
MAT II=ZER
FOR I=1 TO N
LET RR(I)=GAUSSION(I,0,N)
NEXT I
CALL FFT(M,RR,II,1)
CLEAR
SET WINDOW -1000,SAMPLINGFREQ/2,-80,0
DRAW GRID(SAMPLINGFREQ/10,10)
LET LL=SAMPLINGFREQ/2^M
FOR I=1 TO 2^M/2
IF RR(I)=0 AND II(I)=0 THEN
PLOT LINES:I*LL,-80;
ELSE
PLOT LINES:I*LL, 10*LOG10(RR(I)^2+II(I)^2);
END IF
NEXT I
PLOT LINES
WAIT DELAY 1
NEXT N
END
FUNCTION GAUSSION(X,U,A)
LET GAUSSION=1/SQR(2*PI)/A*EXP(-(X-U)^2/(2*A^2))
END FUNCTION
以下略
-------------------------------------------------------------------------------
各種フィルタを試してみた。
LET TAP=16 ! 次数(偶数)
LET M=200 ! サンプル数
DIM DAT(M),OUT(M)
LET SAMPLINGFREQ=44100 ! サンプリング周波数
SET WINDOW 1,M,-1.5,1.5
DRAW GRID(M/4,.3)
FOR I=1 TO M
LET DAT(I)=SIN(1500*I/SAMPLINGFREQ*2*PI)+.3*SIN(12000*I/SAMPLINGFREQ*2*PI) ! 1500Hzと12000Hzの合成波形
PLOT LINES:I,DAT(I);
NEXT I
PLOT LINES
SET LINE COLOR "RED"
LET FILTER=1
CALL FIR(FILTER,DAT,M,TAP,SAMPLINGFREQ,3000,20000,OUT) ! FIRフィルタ処理
FOR I=1 TO M
PLOT LINES:I,OUT(I); ! 結果表示
NEXT I
END
EXTERNAL SUB FIR(FILTER,IN(),SIZE,TAPSIZE,SAMPLINGFREQ,FREQ1,FREQ2,OUT())
DIM COEF(0 TO TAPSIZE)
SELECT CASE FILTER
CASE 1
CALL GETCOEFFICIENTLPF(FREQ1,SAMPLINGFREQ,TAPSIZE,COEF) ! LPF
CASE 2
CALL GETCOEFFICIENTHPF(FREQ1,SAMPLINGFREQ,TAPSIZE,COEF) ! HPF
CASE 3
CALL GETCOEFFICIENTBPF(FREQ1,FREQ2,SAMPLINGFREQ,TAPSIZE,COEF) ! BPF
CASE 4
CALL GETCOEFFICIENTBEF(FREQ1,FREQ2,SAMPLINGFREQ,TAPSIZE,COEF) ! BSF(BEF)
END SELECT
FOR J=1 TO SIZE
LET S=0
FOR I=0 TO TAPSIZE
IF I+J<=SIZE THEN LET S=S+COEF(I)*IN(I+J)
NEXT I
LET OUT(J)=S
NEXT J
END SUB
EXTERNAL SUB GETCOEFFICIENTLPF(FE,SAMPLING,N,H())
LET F = FE /SAMPLING
FOR I=-N/2 TO N/2
IF I = 0 THEN
LET H(N/2+I) = 2.0 * F
ELSE
LET H(N/2+I) = 2.0 * F * SIN(2.0 * PI * F * I)/(2.0 * PI * F *I)
END IF
NEXT I
FOR I=0 TO N
LET H(I)=H(I)*W(I,N) ! 窓関数をかける
NEXT I
END SUB
EXTERNAL SUB GETCOEFFICIENTHPF(FE,SAMPLING,N,H())
LET F = FE /SAMPLING
FOR I=-N/2 TO N/2
IF I = 0 THEN
LET H(N/2+I) = 1.0 - 2.0 * F
ELSE
LET H(N/2+I) = SIN(PI * I) / (PI *I)- 2.0 * F * SIN(2.0 * PI * F * I) / (2.0 * PI * F * I)
END IF
NEXT I
FOR I=0 TO N
LET H(I)=H(I)*W(I,N)
NEXT I
END SUB
EXTERNAL SUB GETCOEFFICIENTBPF(F1,F2,SAMPLING,N,H())
LET FE1 = F1 / SAMPLING
LET FE2 = F2 / SAMPLING
FOR I=-N/2 TO N/2
IF I = 0 THEN
LET H(N/2+I) = 2.0 * (FE2 - FE1)
ELSE
LET H(N/2+I) = 2.0 * FE2 * SIN(2.0 * PI * FE2 * I) / (2.0 * PI * FE2 * I)- 2.0 * FE1 * SIN(2.0 * PI * FE1 * I) / (2.0 * PI * FE1 * I)
END IF
NEXT I
FOR I=0 TO N
LET H(I)=H(I)*W(I,N)
NEXT I
END SUB
EXTERNAL SUB GETCOEFFICIENTBEF(F1,F2,SAMPLING,N,H())
LET FE1 = F1 / SAMPLING
LET FE2 = F2 / SAMPLING
FOR I=-N/2 TO N/2
IF I = 0 THEN
LET H(N/2+I) = 1-2.0 * (FE2 - FE1)
ELSE
LET H(N/2+I) = SIN(2*PI*I)-2.0 * FE2 * SIN(2.0 * PI * FE2 * I) / (2.0 * PI * FE2 * I)+ 2.0 * FE1 * SIN(2.0 * PI * FE1 * I) / (2.0 * PI * FE1 * I)
END IF
NEXT I
FOR I=0 TO N
LET H(I)=H(I)*W(I,N)
NEXT I
END SUB
以下略
-------------------------------------------------------------------------------
上記のフィルタ特性調べてみた。
横軸が周波数、縦軸がdbです。
OPTION BASE 0
LET TAPSIZE=32 ! 次数(偶数)
LET M=8
DIM COEF(TAPSIZE),RR(2^M),II(2^M)
LET SAMPLINGFREQ=44100 ! サンプリング周波数
LET FREQ=10000
LET FREQ1=8000
LET FREQ2=12000
LET FILTER=1
SELECT CASE FILTER
CASE 1
CALL GETCOEFFICIENTLPF(FREQ,SAMPLINGFREQ,TAPSIZE,COEF)
CASE 2
CALL GETCOEFFICIENTHPF(FREQ,SAMPLINGFREQ,TAPSIZE,COEF)
CASE 3
CALL GETCOEFFICIENTBPF(FREQ1,FREQ2,SAMPLINGFREQ,TAPSIZE,COEF)
CASE 4
CALL GETCOEFFICIENTBEF(FREQ1,FREQ2,SAMPLINGFREQ,TAPSIZE,COEF)
END SELECT
FOR I=0 TO TAPSIZE
LET RR(I+1)=COEF(I)
NEXT I
CALL FFT(M,RR,II,1)
SET WINDOW -1000,SAMPLINGFREQ/2,-80,0
DRAW GRID(SAMPLINGFREQ/10,10)
LET LL=SAMPLINGFREQ/2^M
FOR I=1 TO 2^M/2
IF RR(I)=0 AND II(I)=0 THEN
PLOT LINES:I*LL,-80;
ELSE
PLOT LINES:I*LL, 10*LOG10(RR(I)^2+II(I)^2);
END IF
NEXT I
END
以下略
-------------------------------------------------------------------------------
SIN波をFIRフィルタ代わりにしてみた。
RANDOMIZE
LET SAMPLINGFREQ=44100
LET M=12
LET N=2^M
LET SIZE=50
LET FREQ1=1000
LET FREQ2=8000
LET FREQ3=17000
DIM LIN(N)
DIM RR(N),II(N)
FOR I=1 TO N
LET LIN(I)=2*RND-1
! FOR J=1 TO 210
! LET LIN(I)=LIN(I)+SIN(100*J/SAMPLINGFREQ*2*I*PI)/210
! NEXT J
NEXT I
FOR I=1 TO N
LET L=0
FOR J=0 TO SIZE-1
IF I+J<=N THEN
LET S1=SIN(FREQ1/SAMPLINGFREQ*J*2*PI) ! SIN波
LET S2=SIN(FREQ2/SAMPLINGFREQ*J*2*PI)
LET S3=SIN(FREQ3/SAMPLINGFREQ*J*2*PI)
LET L=L+(S1+S2+S3)*LIN(I+J)
END IF
NEXT J
LET RR(I)=L/SIZE
NEXT I
CALL FFT(M,RR,II,1)
SET WINDOW 0,SAMPLINGFREQ/2,-80,30
DRAW GRID(SAMPLINGFREQ/10,10)
LET LL=SAMPLINGFREQ/2^M
FOR I=1 TO 2^M/2
IF RR(I)=0 AND II(I)=0 THEN
PLOT LINES:I*LL,-80;
ELSE
PLOT LINES:I*LL, 10*LOG10(RR(I)^2+II(I)^2);
END IF
NEXT I
END
以下略
Re: FIRフィルタ - しばっち
2024/10/13 (Sun) 08:16:05
下記のようにすれば移動平均(LPF)から別のフィルタを生成できる。
https://vision.kuee.kyoto-u.ac.jp/lecture/dsp/pdf/2013/dsp2013_12.pdf
LET TAP=5 ! 次数
LET SAMPLINGFREQ=2000 ! サンプリング周波数
LET N=SAMPLINGFREQ
DIM IN(N),OUT(N),COEF(TAP)
FOR I=1 TO N
LET IN(I)=SIN(30*I/SAMPLINGFREQ*2*PI)*.8+SIN(800*I/SAMPLINGFREQ*2*PI)*.2
NEXT I
FOR I=1 TO TAP ! 移動平均
LET COEF(I)=1/TAP
NEXT I
LET W0=SAMPLINGFREQ/4
LET MODE=0
SELECT CASE MODE
CASE 0 ! LPF
CASE 1 ! HPF
FOR I=1 TO TAP
LET COEF(I)=(-1)^I*COEF(I)
NEXT I
CASE 2 ! BPF
FOR I=1 TO TAP
LET COEF(I)=2*COS(TAP*W0/SAMPLINGFREQ)*COEF(I)
NEXT I
CASE 3 ! BSF
LET COEF(1)=1-2*COEF(1)
FOR I=2 TO TAP
LET COEF(I)=2*COS(TAP*W0/SAMPLINGFREQ)*COEF(I)
NEXT I
END SELECT
SET WINDOW 1,N/10,-1.5,1.5
DRAW GRID(N/20,.3)
FOR I=1 TO N/10
PLOT LINES:I,IN(I);
NEXT I
PLOT LINES
CALL FIR(IN,N,COEF,TAP,OUT)
SET LINE COLOR "RED"
FOR I=1 TO N/10
PLOT LINES:I,OUT(I);
NEXT I
END
以下略
Re: FIRフィルタ - しばっち
2024/10/13 (Sun) 08:17:07
DCT(離散COS変換)によるフィルタ処理
CALL DCT(X,N,Y)を実行するとN個の配列Xを配列YにDCT変換します。
Y(0)はDC(直流成分)でY(1),Y(2),Y(3)と添え字が大きくなるとAC(交流成分)が高くなり
Y(N-1)が一番高い高周波成分になります。
つまりN=8ではY(7)が一番高い高周波成分になります。
Y(0)=0とすると直流成分遮断になります。
Y(7)=0,Y(6)=0,Y(5)=0のようにすると高周波成分遮断となります。
また、Y(0)=Y(0)*1.2のようにすると増幅となり、Y(0)=Y(0)*.8のように1より小さくすると減衰させることができます。
※NUMはNで割り切れる必要があります。MOD(NUM,N)=0
DECLARE EXTERNAL FUNCTION C
PUBLIC NUMERIC N
LET N=8 ! DCTフィルタ次数
OPTION BASE 0
LET NUM=200
DIM X(N),Y(N),OUT(NUM)
FOR I=1 TO NUM
LET OUT(I)=SIN(400/48000*I*2*PI)*.6+SIN(15000/48000*I*2*PI)*.4
NEXT I
SET WINDOW 0,NUM,-1,1
DRAW GRID(NUM/5,.2)
LET MODE=0
FOR I=1 TO NUM
PLOT LINES:I,OUT(I);
NEXT I
PLOT LINES
FOR I=1 TO NUM STEP N
FOR J=0 TO N-1
LET X(J)=OUT(I+J)
NEXT J
CALL DCT2(X,N,Y) !'離散COSINE変換
SELECT CASE MODE ! フィルタ処理
CASE 0
LET Y(0)=0
CASE 1
LET Y(N-3)=0
LET Y(N-2)=0
LET Y(N-1)=0
CASE 2
LET Y(0)=Y(0)*.7
CASE 3
LET Y(N-3)=Y(N-3)*.5
LET Y(N-2)=Y(N-2)*.5
LET Y(N-1)=Y(N-1)*.5
END SELECT
CALL DCT3(Y,N,X) !'離散COSINE逆変換
FOR J=0 TO N-1
LET OUT(I+J)=X(J)
NEXT J
NEXT I
SET LINE COLOR "RED"
FOR I=1 TO NUM
PLOT LINES:I,OUT(I);
NEXT I
END
EXTERNAL FUNCTION C(X)
IF X=0 OR X=N THEN LET C=SQR(.5) ELSE LET C=1
END FUNCTION
EXTERNAL SUB DCT2(A(),N,B())
FOR I=0 TO N-1
LET S=0
FOR K=0 TO N-1
LET S=S+A(K)*COS((2*K+1)*I*PI/2/N)
NEXT K
LET B(I)=S*SQR(2/N)*C(I)
NEXT I
END SUB
EXTERNAL SUB DCT3(A(),N,B())
FOR I=0 TO N-1
LET S=0
FOR K=0 TO N-1
LET S=S+C(K)*A(K)*COS((2*I+1)*K*PI/2/N)
NEXT K
LET B(I)=S*SQR(2/N)
NEXT I
END SUB
-----------------------------------------------------------------------------------
周波数特性調べてみた。
RANDOMIZE
DECLARE EXTERNAL FUNCTION C
LET M=12
OPTION BASE 0
LET SAMPLINGFREQ=44100
LET NUM=2^M
DIM RR(NUM),II(NUM),X(64),Y(64)
LET NN=8
DO
CLEAR
MAT RR=ZER
MAT II=ZER
FOR I=1 TO NUM
LET RR(I)=2*RND-1
NEXT I
LET MODE=1
FOR I=1 TO NUM STEP NN
FOR J=0 TO NN-1
LET X(J)=RR(I+J)
NEXT J
CALL DCT2(X,NN,Y) !'離散COSINE変換
SELECT CASE MODE
CASE 0
LET Y(0)=0
LET Y(1)=0
LET Y(2)=0
CASE 1
FOR J=1 TO NN-1
LET Y(J)=0
NEXT J
END SELECT
CALL DCT3(Y,NN,X) !'離散COSINE逆変換
FOR J=0 TO NN-1
LET RR(I+J)=X(J)
NEXT J
NEXT I
CALL FFT(M,RR,II,1)
SET WINDOW -15,SAMPLINGFREQ/2,-30,40
DRAW GRID(SAMPLINGFREQ/10,10)
LET LL=SAMPLINGFREQ/NUM
FOR I=1 TO NUM/2
IF RR(I)=0 AND II(I)=0 THEN
PLOT LINES:I*LL,-30;
ELSE
PLOT LINES:I*LL, 10*LOG10(RR(I)^2+II(I)^2);
END IF
NEXT I
WAIT DELAY 1
LET NN=NN*2
LOOP UNTIL NN>64
END
以下略
Re: FIRフィルタ - しばっち
2024/10/13 (Sun) 08:18:06
下記プログラムはDCTフィルタ次数を8として逆DCTの次数を増減させている。
これは画像処理でいう拡大・縮小処理にあたります。
つまり拡大にあたる処理では周波数は減衰し縮小では周波数が増大します。
これは全体のサイズが変化しているためです。
黒線が処理前のパワースペクトルで200Hzが高くなっています。
赤線がDCT処理後のパワースペクトルです。
DECLARE EXTERNAL FUNCTION C
PUBLIC NUMERIC NN
LET NN=8 ! DCT次数
LET M=8 ! FFT次数
OPTION BASE 0
LET NUM=2^M
LET SAMPLINGFREQ=1000 ! サンプリング周波数
DIM X(NN*2),Y(NN*2),RR(NUM*2),II(NUM*2)
DIM TR(NUM*2)
CALL SETDATA
CALL DISPLAY
CALL SETDATA
FOR I=1 TO NUM STEP NN
FOR J=0 TO NN-1
LET X(J)=RR(I+J)
NEXT J
LET MM=NN/2 ! 縮小
!LET MM=NN*2 ! 拡大
CALL DCT2(X,NN,Y) !'離散COSINE変換
CALL DCT3(Y,MM,X) !'離散COSINE逆変換
FOR J=0 TO MM-1
LET TR(JJ+J)=X(J)
NEXT J
LET JJ=JJ+MM
NEXT I
MAT RR=TR
SET LINE COLOR "RED"
CALL DISPLAY
SUB SETDATA
MAT II=ZER
FOR I=1 TO NUM
LET RR(I)=SIN(200/SAMPLINGFREQ*I*2*PI)
NEXT I
END SUB
SUB DISPLAY
MAT II=ZER
CALL FFT(M,RR,II,1)
SET WINDOW -15,SAMPLINGFREQ/2,-10,40
DRAW GRID(SAMPLINGFREQ/10,10)
LET LL=SAMPLINGFREQ/NUM
FOR I=1 TO 2^M/2
IF RR(I)=0 AND II(I)=0 THEN
PLOT LINES:I*LL,-10;
ELSE
PLOT LINES:I*LL, 10*LOG10(RR(I)^2+II(I)^2);
END IF
NEXT I
PLOT LINES
END SUB
END
以下略
Re: FIRフィルタ - しばっち
2024/10/13 (Sun) 08:19:23
ウェーブレット変換の周波数特性を調べてみた。
RANDOMIZE
OPTION BASE 0
LET M=16
LET NUM=2^M
FOR LEV=1 TO 4
LET SIZE=INT((NUM+2^LEV-1)/2^LEV)*2^LEV
DIM DAT1(SIZE),DAT2(SIZE),II(SIZE)
FOR I=0 TO NUM-1
LET DAT1(I)=2*RND-1
LET DAT2(I+1)=DAT1(I)
NEXT I
MAT II=ZER
CALL FFT(M,DAT2,II,1)
CLEAR
SET WINDOW 1,NUM/2,-50,70
DRAW GRID(NUM/10,10)
FOR I=1 TO NUM/2
IF DAT2(I)<>0 OR II(I)<>0 THEN
PLOT LINES:I,10*LOG10(DAT2(I)^2+II(I)^2);
ELSE
PLOT LINES:I,-50;
END IF
NEXT I
PLOT LINES
MAT DAT2=ZER
WAIT DELAY 1
CLEAR
CALL WAVELET1D(LEV,1,SIZE,DAT1,DAT2)
LET MODE=1
SELECT CASE MODE
CASE 0
FOR I=0 TO SIZE/2^LEV-1
LET DAT2(I)=0
NEXT I
CASE 1
FOR I=SIZE/2^LEV TO SIZE-1
LET DAT2(I)=0 ! フィルタ処理
NEXT I
END SELECT
MAT DAT1=ZER
CALL IWAVELET1D(LEV,1,SIZE,DAT2,DAT1)
FOR I=0 TO SIZE-1
LET DAT2(I+1)=DAT1(I)
NEXT I
MAT II=ZER
CALL FFT(M,DAT2,II,1)
SET WINDOW 1,NUM/2,-50,70
DRAW GRID(NUM/10,10)
FOR I=1 TO NUM/2
IF DAT2(I)<>0 OR II(I)<>0 THEN
PLOT LINES:I,10*LOG10(DAT2(I)^2+II(I)^2);
ELSE
PLOT LINES:I,-50;
END IF
NEXT I
NEXT LEV
END
EXTERNAL SUB WAVELET1D(LEV,XS,SIZE,DAT1(),DAT2())
OPTION BASE 0
DIM X(SIZE),Y(SIZE)
IF LEV>0 THEN
FOR I=0 TO SIZE-1
LET X(I)=DAT1(I+XS)
NEXT I
CALL WAVELET(SIZE,X,Y)
FOR I=0 TO SIZE-1
LET DAT2(I+XS)=Y(I)
NEXT I
FOR I=0 TO SIZE-1
LET DAT1(I+XS)=DAT2(I+XS)
NEXT I
CALL WAVELET1D(LEV-1,XS,SIZE/2,DAT1,DAT2)
CALL WAVELET1D(LEV-1,XS+SIZE/2,SIZE/2,DAT1,DAT2)
END IF
END SUB
EXTERNAL SUB IWAVELET1D(LEV,XS,SIZE,DAT1(),DAT2())
OPTION BASE 0
DIM X(SIZE),Y(SIZE)
IF LEV>0 THEN
CALL IWAVELET1D(LEV-1,XS,SIZE/2,DAT1,DAT2)
CALL IWAVELET1D(LEV-1,XS+SIZE/2,SIZE/2,DAT1,DAT2)
FOR I=0 TO SIZE-1
LET X(I)=DAT1(I+XS)
NEXT I
CALL IWAVELET(SIZE,X,Y)
FOR I=0 TO SIZE-1
LET DAT2(I+XS)=Y(I)
NEXT I
FOR I=0 TO SIZE-1
LET DAT1(I+XS)=DAT2(I+XS)
NEXT I
END IF
END SUB
EXTERNAL SUB WAVELET(SIZE,DAT1(),DAT2())
FOR I=0 TO SIZE/2-1
LET DAT2(I)=.5*DAT1(I*2)+.5*DAT1(I*2+1)
LET DAT2(I+SIZE/2)=.5*DAT1(I*2)-.5*DAT1(I*2+1)
NEXT I
END SUB
EXTERNAL SUB IWAVELET(SIZE,DAT2(),DAT1())
FOR I=0 TO SIZE/2-1
LET DAT1(I*2)=DAT2(I)+DAT2(I+SIZE/2)
LET DAT1(I*2+1)=DAT2(I)-DAT2(I+SIZE/2)
NEXT I
END SUB
以下略
Re: FIRフィルタ - しばっち
2024/10/13 (Sun) 08:20:36
アダマール変換の周波数特性調べてみた。
LET M=12
LET SAMPLINGFREQ=44100
OPTION BASE 0
RANDOMIZE
LET NUM=2^M
DIM RR(NUM),II(NUM),X(2^8),Y(2^8)
LET LL=SAMPLINGFREQ/NUM
FOR BIT=3 TO 8
CLEAR
MAT RR=ZER
MAT II=ZER
LET N=2^BIT
FOR I=1 TO NUM
LET RR(I)=2*RND-1
NEXT I
FOR I=1 TO NUM STEP N
FOR J=0 TO N-1
LET X(J)=RR(I+J)
NEXT J
CALL FASTHADAMARD(X,N,Y)
FOR J=1 TO N-1
LET K=SEQUENCY(BIT,J)
LET Y(K)=0
NEXT J
CALL FASTHADAMARD(Y,N,X)
FOR J=0 TO N-1
LET RR(I+J)=X(J)/N
NEXT J
NEXT I
CALL FFT(M,RR,II,1)
SET WINDOW 1,SAMPLINGFREQ/2,-60,40
DRAW GRID(SAMPLINGFREQ/10,10)
FOR I=1 TO NUM/2
IF RR(I)=0 AND II(I)=0 THEN
PLOT LINES:I*LL,-60;
ELSE
PLOT LINES:I*LL,10*LOG10(RR(I)^2+II(I)^2);
END IF
NEXT I
WAIT DELAY 1
NEXT BIT
END
EXTERNAL SUB FASTHADAMARD(X(),N,A()) ! 高速アダマール変換
LET BIT=LOG2(N)
FOR J=1 TO BIT
LET K=0
LET L=0
FOR I=0 TO N-1
IF I<N/2 THEN
LET A(I)=X(2*K)+X(2*K+1)
LET K=K+1
ELSE
LET A(I)=X(2*L)-X(2*L+1)
LET L=L+1
END IF
NEXT I
MAT X=A
NEXT J
END SUB
EXTERNAL FUNCTION SEQUENCY(BIT,N)
FOR I=1 TO BIT
LET G=BITAND(N,1)
LET N=INT(N/2)
LET L=BITXOR(G,B)
LET A=A*2+L
LET B=L
NEXT I
LET SEQUENCY=A
END FUNCTION
Re: FIRフィルタ - しばっち
2024/10/13 (Sun) 08:21:53
位相シフト
位相を任意のシフト幅でずらします。
LET SAMPLINGFREQ=50 ! サンプリング周波数
SET WINDOW 1,SAMPLINGFREQ,-1,1
DRAW GRID(SAMPLINGFREQ/10,.2)
LET TH=PI/6 ! シフト幅
LET FREQ=4 ! 周波数
LET D=SAMPLINGFREQ/(4*FREQ)
DIM A(SAMPLINGFREQ+D)
FOR I=1 TO SAMPLINGFREQ+D
LET A(I)=SIN(FREQ/SAMPLINGFREQ*I*2*PI)
PLOT LINES:I,A(I); ! 元波形
NEXT I
PLOT LINES
SET LINE COLOR "BLUE"
FOR I=1 TO SAMPLINGFREQ
PLOT LINES:I,SIN(FREQ/SAMPLINGFREQ*I*2*PI+TH); !位相シフトした波形
NEXT I
PLOT LINES
SET LINE COLOR "RED"
FOR I=1 TO SAMPLINGFREQ
! PLOT LINES:I,SIN(FREQ/SAMPLINGFREQ*I*2*PI)*COS(TH)+COS(FREQ/SAMPLINGFREQ*I*2*PI)*SIN(TH); ! 加法定理 SIN(A+B)=SIN(A)*COS(B)+COS(A)*SIN(B)
PLOT LINES:I,A(I)*COS(TH)+A(I+D)*SIN(TH);
NEXT I
END
FFTフィルタ処理 - しばっち
2024/10/13 (Sun) 08:00:23
FFTフィルタ処理
https://decimalbasic.ninja-web.net/bbs2/4366.html
https://decimalbasic.ninja-web.net/bbs2/4367.html
https://decimalbasic.ninja-web.net/bbs2/4368.html
https://decimalbasic.ninja-web.net/bbs2/4559.html
FFTによるフィルタを定義してみました。
処理前と処理後の違いをグラフ表示しています。
サンプリング周波数を400Hzとし、合成波形を生成して
各種フィルタ処理してみました。
(※フィルタ処理可能域はサンプリング定理によりサンプリング周波数の半分までです。ナイキスト周波数)
https://ja.wikipedia.org/wiki/標本化定理
https://ja.wikipedia.org/wiki/ナイキスト周波数
https://ja.wikipedia.org/wiki/ローパスフィルタ
フィルタ処理により波形が変化していることを確認してください。
2進モードで実行してください。
サンプル数2^24個のFFT演算が600秒あまりでした。
LET M=8
LET N=2^M ! FFTサンプル数
DIM RR(N),II(N),T(N)
MAT T=CON
LET FREQ=400 ! サンプリング周波数
FOR I=1 TO N
LET RR(I)=SIN(20/FREQ*I*2*PI)*.5+.3*SIN(120/FREQ*I*2*PI)+.1*SIN(180/FREQ*I*2*PI) ! 20Hz,120Hz,180Hzの合成波形
NEXT I
SET WINDOW -3,64,-1.5,1.5
DRAW GRID(4,.2)
FOR I=1 TO 64
PLOT LINES: I,RR(I); ! グラフ表示
NEXT I
CALL FFT(M,RR,II,1) ! FFT
LET FILTER=0
SELECT CASE FILTER
CASE 0
LET F=100/FREQ*N ! 遮断域周波数 100Hz~
FOR I=F TO N-F ! ローパスフィルタ LPF
LET RR(I)=0
LET II(I)=0
LET T(I)=0
NEXT I
CASE 1
LET F=150/FREQ*N ! 通過域周波数 150Hz~
FOR I=1 TO F ! ハイパスフィルタ HPF
LET RR(I)=0
LET II(I)=0
LET T(I)=0
NEXT I
FOR I=N-F TO N
LET RR(I)=0
LET II(I)=0
LET T(I)=0
NEXT I
CASE 2
LET FS=80/FREQ*N ! 通過域周波数 80Hz~150Hz
LET FE=150/FREQ*N
FOR I=1 TO FS ! バンドパスフィルタ BPF
LET RR(I)=0
LET II(I)=0
LET T(I)=0
NEXT I
FOR I=FE TO N-FE
LET RR(I)=0
LET II(I)=0
LET T(I)=0
NEXT I
FOR I=N-FS TO N
LET RR(I)=0
LET II(I)=0
LET T(I)=0
NEXT I
CASE 3
LET FS=80/FREQ*N ! 遮断域周波数 80Hz~150Hz
LET FE=150/FREQ*N
FOR I=FS TO FE ! バンドストップフィルタ BSF(BEF)
LET RR(I)=0
LET II(I)=0
LET T(I)=0
NEXT I
FOR I=N-FE TO N-FS
LET RR(I)=0
LET II(I)=0
LET T(I)=0
NEXT I
CASE 4
LET F=120/FREQ*N
FOR I=F-1 TO F+1 ! ノッチ
LET RR(I)=0
LET II(I)=0
LET T(I)=0
LET RR(N-I)=0
LET II(N-I)=0
LET T(N-I)=0
NEXT I
CASE 5
LET F=120/FREQ*N
FOR I=1 TO F-2 ! 逆ノッチ
LET RR(I)=0
LET II(I)=0
LET T(I)=0
NEXT I
FOR I=F+2 TO N-F-1
LET RR(I)=0
LET II(I)=0
LET T(I)=0
NEXT I
FOR I=N-F+1 TO N
LET RR(I)=0
LET II(I)=0
LET T(I)=0
NEXT I
CASE 6
LET FS=80/FREQ*N
LET FE=150/FREQ*N
FOR I=FS TO FE ! オールパスフィルタ
LET II(I)=-II(I) ! 位相反転
NEXT I
FOR I=N-FE TO N-FS
LET II(I)=-II(I)
NEXT I
FOR I=N-FS TO N
LET II(I)=-II(I)
NEXT I
END SELECT
PAUSE
CLEAR
SET WINDOW -10,N/2,-.1,1.1
DRAW GRID(16,.2)
FOR X=1 TO N/2
PLOT LINES:X,T(X); ! フィルタ形状(0=遮断,1=通過)
NEXT X
PAUSE
CLEAR
CALL FFT(M,RR,II,-1) ! 逆FFT
SET WINDOW -3,64,-1.5,1.5
DRAW GRID(4,.2)
FOR I=1 TO 64
PLOT LINES: I,RR(I); ! 波形表示
NEXT I
END
EXTERNAL SUB FFT(M,XR(),XI(),INVERSE)
LET N=2^M
LET L=N/2
LET J=L+1
FOR I=2 TO N-2
IF I<J THEN
SWAP XR(I),XR(J)
SWAP XI(I),XI(J)
END IF
LET K=L
DO WHILE K<J
LET J=J-K
LET K=K/2
LOOP
LET J=J+K
NEXT I
IF INVERSE=1 THEN
LET PX=-PI
ELSE
FOR I=1 TO N
LET XR(I)=XR(I)/N
LET XI(I)=XI(I)/N
NEXT I
LET PX=PI
END IF
LET L=1
FOR K=1 TO M
LET LL=L+L
LET P=PX/L
FOR J=1 TO L
LET W=(J-1)*P
LET WR=COS(W)
LET WI=SIN(W)
FOR I=J TO N STEP LL
LET IL=I+L
LET TR=XR(IL)*WR-XI(IL)*WI
LET TI=XR(IL)*WI+XI(IL)*WR
LET XR(IL)=XR(I)-TR
LET XI(IL)=XI(I)-TI
LET XR(I)=XR(I)+TR
LET XI(I)=XI(I)+TI
NEXT I
NEXT J
LET L=LL
NEXT K
END SUB
-------------------------------------------------------------------------
グラフ表示だけではおもしろくないのでwavファイルに書き出して
聞き比べられるようにしてみました。※スピーカーのボリュームは小さめにしてください。
サンプル数2^17(131072)でサンプリング周波数44100Hzなので再生時間は131072/44100=2.97215でおよそ3秒になります。
LET M=17
LET N=2^M ! FFTサンプル数
DIM RR(N),II(N)
LET SAMPLINGFREQ=44100 ! サンプリング周波数
LET VOL=.5 ! ボリューム
FOR I=1 TO N
LET RR(I)=SIN(800/SAMPLINGFREQ*I*2*PI)+.3*SIN(4000/SAMPLINGFREQ*I*2*PI)+.1*SIN(12000/SAMPLINGFREQ*I*2*PI) ! 800Hzと4000Hzと12000Hzの合成波形
LET RR(I)=RR(I)*VOL
NEXT I
CALL WRITEWAV("元音.wav",N,SAMPLINGFREQ,16,RR) ! モノラル版
CALL FFT(M,RR,II,1) ! FFT
LET FILTER=0
SELECT CASE FILTER
CASE 0
LET F=1000/SAMPLINGFREQ*N
FOR I=F+1 TO N-F-1 ! ローパスフィルタ LPF
LET RR(I)=0
LET II(I)=0
NEXT I
CASE 1
LET F=10000/SAMPLINGFREQ*N
FOR I=1 TO F ! ハイパスフィルタ HPF
LET RR(I)=0
LET II(I)=0
NEXT I
FOR I=N-F TO N
LET RR(I)=0
LET II(I)=0
NEXT I
CASE 2
LET FS=1000/SAMPLINGFREQ*N
LET FE=5000/SAMPLINGFREQ*N
FOR I=1 TO FS-1 ! バンドパスフィルタ BPF
LET RR(I)=0
LET II(I)=0
NEXT I
FOR I=FE+1 TO N-FE
LET RR(I)=0
LET II(I)=0
NEXT I
FOR I=N-FS TO N
LET RR(I)=0
LET II(I)=0
NEXT I
CASE 3
LET FS=1000/SAMPLINGFREQ*N
LET FE=5000/SAMPLINGFREQ*N
FOR I=FS TO FE ! バンドストップフィルタ BSF(BEF)
LET RR(I)=0
LET II(I)=0
NEXT I
FOR I=N-FE TO N-FS
LET RR(I)=0
LET II(I)=0
NEXT I
END SELECT
CALL FFT(M,RR,II,-1) ! 逆FFT
CALL WRITEWAV("処理後.wav",N,SAMPLINGFREQ,16,RR)
END
以下略
-------------------------------------------------------------------------
FFT係数を増幅して元信号を増幅できるか試してみた。
LET M=8
LET N=2^M
DIM RR(N),II(N)
LET SAMPLINGFREQ=1000 ! サンプリング周波数
SET WINDOW 1,N/2,-1.5,1.5
DRAW GRID(N/8,.5)
FOR I=1 TO N
LET RR(I)=SIN(50/SAMPLINGFREQ*I*2*PI)*.8+SIN(300/SAMPLINGFREQ*I*2*PI)*.2
NEXT I
FOR I=1 TO N/2
PLOT LINES:I,RR(I);
NEXT I
LET DB=10
LET GAIN=10^(DB/20) ! 増幅率10db
LET FILTER=0
CALL FFTFILTER(M,FILTER,SAMPLINGFREQ,100,400,GAIN,RR,II)
PAUSE
CLEAR
SET WINDOW 1,N/2,-1.5,1.5
DRAW GRID(N/8,.5)
FOR I=1 TO N/2
PLOT LINES:I,RR(I);
NEXT I
END
EXTERNAL SUB FFTFILTER(M,FILTER,SAMPLINGFREQ,FREQ1,FREQ2,GAIN,RR(),II())
LET N=2^M
LET F=FREQ1/SAMPLINGFREQ*N
LET FS=FREQ1/SAMPLINGFREQ*N
LET FE=FREQ2/SAMPLINGFREQ*N
CALL FFT(M,RR,II,1) ! FFT
SELECT CASE FILTER
CASE 0
FOR I=F+1 TO N-F-1 ! ハイシェルフ
LET RR(I)=RR(I)*GAIN
NEXT I
CASE 1
FOR I=1 TO F ! ロ-シェルフ
LET RR(I)=RR(I)*GAIN
NEXT I
FOR I=N-F TO N
LET RR(I)=RR(I)*GAIN
NEXT I
CASE 2
FOR I=1 TO FS-1 ! 反バンド増幅
LET RR(I)=RR(I)*GAIN
NEXT I
FOR I=FE+1 TO N-FE
LET RR(I)=RR(I)*GAIN
NEXT I
FOR I=N-FS TO N
LET RR(I)=RR(I)*GAIN
NEXT I
CASE 3
FOR I=FS TO FE ! バンド増幅
LET RR(I)=RR(I)*GAIN
NEXT I
FOR I=N-FE TO N-FS
LET RR(I)=RR(I)*GAIN
NEXT I
END SELECT
CALL FFT(M,RR,II,-1) ! 逆FFT
END SUB
以下略
-------------------------------------------------------------------------
FFT係数をシフトすることで元周波数を変更(ピッチシフト)できるか試してみた。
このプログラムではシフト幅100Hzとすると
100Hz→200Hz
200Hz→300Hz
400Hz→500Hz
800Hz→900Hz
のようにするので和音などの響きが乱れることになります。
次のように
100Hz→200Hz
200Hz→400Hz
400Hz→800Hz
800Hz→1600Hz
とすれば乱れることなく音程を1オクターブ上げる(ピッチアップ)ことができます。
※赤線と青線が一致するのが理想ですが、実際には一致しません。
LET M=10
LET N=2^M ! FFTポイント数
DIM RR(N),II(N)
DIM AR(N),AI(N)
LET SAMPLINGFREQ=2000 ! サンプリング周波数
LET LL=SAMPLINGFREQ/N
LET FREQ=300 ! 周波数
LET SHIFTFREQ=300 ! シフト幅周波数
LET SHIFT=SHIFTFREQ/SAMPLINGFREQ*N
FOR I=1 TO N
LET RR(I)=SIN(FREQ/SAMPLINGFREQ*I*2*PI)
NEXT I
SET WINDOW 1,N/16,-3,3
DRAW GRID(N/64,1)
FOR I=1 TO N/16
PLOT LINES:I,RR(I); ! 元波形表示
NEXT I
PAUSE
CLEAR
PLOT LINES
CALL FFT(M,RR,II,1) ! FFT
SET WINDOW 1,SAMPLINGFREQ/2,-30,50
DRAW GRID(SAMPLINGFREQ/10,10)
FOR I=1 TO N/2
PLOT LINES:I*LL,10*LOG10(RR(I)^2+II(I)^2); ! 振幅スペクトル
NEXT I
PLOT LINES
LET MODE=1
SELECT CASE MODE
CASE 1 ! ピッチシフトアップ
FOR I=1 TO N/2-SHIFT
LET AR(I+SHIFT)=RR(I)
LET AI(I+SHIFT)=II(I)
NEXT I
FOR I=N/2 TO N-SHIFT
LET AR(I)=RR(I+SHIFT)
LET AI(I)=II(I+SHIFT)
NEXT I
CASE 2 ! ピッチシフトダウン
FOR I=1 TO N/2-SHIFT
LET AR(I)=RR(I+SHIFT)
LET AI(I)=II(I+SHIFT)
NEXT I
FOR I=N/2 TO N-SHIFT
LET AR(I+SHIFT)=RR(I)
LET AI(I+SHIFT)=II(I)
NEXT I
END SELECT
SET LINE COLOR "RED"
FOR I=1 TO N/2
PLOT LINES:I*LL,10*LOG10(AR(I)^2+AI(I)^2+1); ! シフトした振幅スペクトル
NEXT I
PAUSE
CLEAR
PLOT LINES
CALL FFT(M,AR,AI,-1) ! 逆FFT
CALL FFT(M,RR,II,-1) ! 逆FFT
SET WINDOW 1,N/16,-3,3
DRAW GRID(N/64,1)
SET LINE COLOR "BLACK"
FOR I=1 TO N/16
PLOT LINES:I,RR(I); ! 元波形
NEXT I
PLOT LINES
SET LINE COLOR "RED"
FOR I=1 TO N/16
PLOT LINES:I,AR(I); ! シフト波形
NEXT I
PLOT LINES
SET LINE COLOR "BLUE"
FOR I=1 TO N
LET RR(I)=SIN((FREQ+SHIFTFREQ)/SAMPLINGFREQ*I*2*PI) ! ピッチシフトした理想的な波形
NEXT I
FOR I=1 TO N/16
PLOT LINES:I,RR(I);
NEXT I
END
以下略
----------------------------------------------------------------------------------
位相シフトできるか試してみた。
LET M=8
LET N=2^M
DIM RR(N),II(N),FI(N)
LET FREQ=400
FOR I=1 TO N
LET RR(I)=SIN(20/FREQ*I*2*PI)+.2*SIN(180/FREQ*I*2*PI)
NEXT I
SET WINDOW 1,N,-1,1
DRAW GRID(N/10,.2)
FOR I=1 TO N
PLOT LINES: I,RR(I);
NEXT I
PLOT LINES
CALL FFT(M,RR,II,1)
LET SHIFT=3
FOR I=1 TO N
IF I+SHIFT<=N THEN LET FI(I)=II(I+SHIFT) ELSE LET FI(I)=II(I)
NEXT I
CALL FFT(M,RR,FI,-1)
SET LINE COLOR "RED"
FOR I=1 TO N
PLOT LINES: I,RR(I);
NEXT I
END
以下略
----------------------------------------------------------------------------------
ノイズ生成
https://ja.wikipedia.org/wiki/ホワイトノイズ
https://moge32.blogspot.com/2019/01/blog-post.html
https://achapi2718.blogspot.com/2014/03/c_4061.html
https://ja.wikipedia.org/wiki/カラードノイズ
http://www.finetune.co.jp/~lyuka/technote/pinknoise/
https://zenn.dev/shin1007/articles/d0a1e59d8ca69c
ホワイトノイズ
ホワイトノイズは全ての周波数で同じ強度となるノイズです。
※再生時、スピーカーのボリュームに気を付けてください。
RANDOMIZE
LET SAMPLINGFREQ=44100 ! サンプリング周波数
LET PLAYTIME=2
LET NUM=SAMPLINGFREQ*PLAYTIME
LET M=INT(LOG2(NUM))+1
LET N=2^M ! FFTサンプル数
DIM RR(N),II(N)
LET VOL=.4
SET WINDOW 1,NUM,-1,1
DRAW GRID(NUM/8,.2)
FOR I=1 TO NUM
LET RR(I)=(2*RND-1)*VOL
PLOT LINES:I,RR(I);
NEXT I
CALL WRITEWAV("ホワイトノイズ.wav",NUM,SAMPLINGFREQ,16,RR)
CALL FFT(M,RR,II,1) ! FFT
PLOT LINES
CLEAR
SET WINDOW 1,SAMPLINGFREQ/2,0,60
DRAW GRID(SAMPLINGFREQ/10,10)
LET LL=SAMPLINGFREQ/N
FOR I=1 TO N/2
PLOT LINES:I*LL,10*LOG10(RR(I)^2+II(I)^2);
NEXT I
END
以下略
----------------------------------------------------------------------------------
ピンクノイズ
周波数が10倍ごとに10dB減衰します(-10dB/decade)
https://ja.wikipedia.org/wiki/ピンクノイズ
https://marui.hatenablog.com/entry/2017/07/17/173904
※再生時、スピーカーのボリュームに気を付けてください。
RANDOMIZE
LET SAMPLINGFREQ=44100 ! サンプリング周波数
LET PLAYTIME=2 ! 演奏時間
LET NUM=SAMPLINGFREQ*PLAYTIME
LET M=INT(LOG2(NUM))+1
LET N=2^M ! FFTサンプル数
DIM RR(N),II(N)
LET VOL=.4
FOR I=1 TO NUM
LET RR(I)=(2*RND-1)*VOL ! ホワイトノイズ
NEXT I
CALL FFT(M,RR,II,1) ! FFT
FOR I=1 TO N ! フィルタ処理
LET RR(I)=RR(I)/I ! ピンクノイズ 1/f
LET II(I)=II(I)/I
NEXT I
SET WINDOW 1,LOG10(SAMPLINGFREQ/2),-60,10
SET LINE STYLE 3
FOR Y=-60 TO 10 STEP 3
PLOT LINES:1,Y;LOG10(SAMPLINGFREQ/2),Y
NEXT Y
FOR I=1 TO 5
FOR J=1 TO 9
LET X=J*10^I
PLOT LINES:LOG10(X),10;LOG10(X),-60
NEXT J
NEXT I
SET LINE STYLE 1
LET LL=SAMPLINGFREQ/N ! 分解能
FOR I=1 TO N/2
PLOT LINES:LOG10(I*LL),-60;LOG10(I*LL),10*LOG10(RR(I)^2+II(I)^2) ! 対数振幅グラフ
NEXT I
CALL FFT(M,RR,II,-1) ! 逆FFT
FOR I=1 TO NUM
LET LMAX=MAX(ABS(RR(I)),LMAX)
NEXT I
FOR I=1 TO NUM ! 正規化
LET RR(I)=RR(I)/LMAX
NEXT I
CALL WRITEWAV("ピンクノイズ.wav",NUM,SAMPLINGFREQ,16,RR)
END
以下略
----------------------------------------------------------------------------------
ケプストラム分析
https://ja.wikipedia.org/wiki/ケプストラム
https://nettyukobo.com/cepstrum/
https://ja.wikipedia.org/wiki/フォルマント
https://contest.japias.jp/tqj17/170282/home/h04-2.html
https://www.gavo.t.u-tokyo.ac.jp/~mine/japanese/nlp+slp/I-RO-HA.pdf
マイクからサウンドレコーダーで録音した「あ」のwavファイルを読み込み
スペクトル包絡を求めています。(サンプル画像 赤線グラフ)
それらから極大値(ピーク)を幾つか抽出できれば「あ」の
フォルマント周波数が求められる。(音声「あ」を構成する周波数)
LET SIZE=44100*20
DIM LIN(SIZE),RIN(SIZE)
FILE GETOPENNAME F$,"読み込み WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN,ERR)
IF ERR>0 THEN STOP
LET M=INT(LOG2(NUM)+1)
LET NN=2^M
LET L=72
LET EPS=1E-15
DIM LR(NN),LI(NN),LLOG(NN),LTMP(NN)
DIM LCL(NN)
FOR I=1 TO NUM
LET LR(I)=LIN(I)*W(I,NUM)
NEXT I
CALL FFT(M,LR,LI,1)
LET LL=SAMPLINGFREQ/NUM
SET WINDOW -1000,SAMPLINGFREQ/2,-50,30
DRAW GRID(SAMPLINGFREQ/8,10)
FOR I=1 TO NN
LET LLOG(I)=LOG(LR(I)^2+LI(I)^2+EPS)
NEXT I
FOR I=1 TO NN/2
PLOT LINES:I*LL,10*LOG10(LLOG(I)^2+EPS);
NEXT I
PLOT LINES
MAT LTMP=ZER
CALL FFT(M,LLOG,LTMP,-1)
MAT LCL=LLOG
FOR I=L TO NN-L
LET LCL(I)=0
NEXT I
MAT LTMP=ZER
CALL FFT(M,LCL,LTMP,1)
SET LINE COLOR "RED"
SET LINE WIDTH 3
FOR I=1 TO NN/2
PLOT LINES:I*LL,10*LOG10(LCL(I)^2+EPS);
NEXT I
END
以下略
Re: FFTフィルタ処理 - しばっち
2024/10/13 (Sun) 08:02:05
ナイキスト周波数
https://ja.wikipedia.org/wiki/ナイキスト周波数
ナイキスト周波数(サンプリング周波数の半分)を超えると下記のようになります。
LET SAMPLINGFREQ=8000 ! サンプリング周波数
LET FREQ1=1000
LET FREQ2=SAMPLINGFREQ-FREQ1 ! SAMPLINGFREQ/2<FREQ2
LET NUM=30
SET WINDOW 1,NUM,-1,1
DRAW GRID(NUM/5,.2)
FOR I=1 TO NUM
PLOT LINES:I,SIN(FREQ1/SAMPLINGFREQ*I*2*PI);
NEXT I
PLOT LINES
SET LINE COLOR "RED"
FOR I=1 TO NUM
PLOT LINES:I,SIN(FREQ2/SAMPLINGFREQ*I*2*PI);
NEXT I
END
位相がずれていますが、周期は同じになります。
位相のずれは画像では表示位置のずれとして認知できますが
音の位相ずれは聞き分けられません。
LET SAMPLINGFREQ=8000 ! サンプリング周波数
LET FREQ1=1000
LET FREQ2=SAMPLINGFREQ-FREQ1 ! SAMPLINGFREQ/2<FREQ2
LET NUM=SAMPLINGFREQ*3
LET VOL=.5
DIM LOUT(NUM)
FOR I=1 TO NUM
LET LOUT(I)=SIN(FREQ1/SAMPLINGFREQ*I*2*PI)*VOL
NEXT I
CALL WRITEWAV("原音.WAV",NUM,SAMPLINGFREQ,16,LOUT)
FOR I=1 TO NUM
LET LOUT(I)=SIN(FREQ2/SAMPLINGFREQ*I*2*PI)*VOL
NEXT I
CALL WRITEWAV("位相ずれ.WAV",NUM,SAMPLINGFREQ,16,LOUT)
END
以下略
Re: FFTフィルタ処理 - しばっち
2024/10/13 (Sun) 08:03:18
周波数解析
FFTを使用しない簡易的な方法ですが周期性を探し出しています。
LET SAMPLINGFREQ=48000
!LET SAMPLINGFREQ=44100
LET N=20
LET SMIN=1E+10
LET FREQ=400
LET START=1
LET NUM=SAMPLINGFREQ
DIM IN(NUM)
FOR I=1 TO NUM
LET IN(I)=SIN(FREQ/SAMPLINGFREQ*I*2*PI)
NEXT I
FOR K=3 TO SAMPLINGFREQ/2-1 !ナイキスト周波数まで探索
LET S=0
FOR J=0 TO N-1
LET S=S+(IN(START+J)-IN(START+J+K))^2 ! S=0なら周期一致
NEXT J
IF S<SMIN THEN
IF SMIN<1E+10 THEN PRINT SAMPLINGFREQ/K;"Hz"
LET SMIN=S
END IF
NEXT K
END
-----------------------------------------------------------------------------
相関係数で周期性を探し出します。
LET SAMPLINGFREQ=48000
LET NUM=SAMPLINGFREQ
LET FREQ=400
LET N=50
DIM IN(NUM),A(N),B(N)
FOR I=1 TO NUM
LET IN(I)=SIN(FREQ/SAMPLINGFREQ*I*2*PI)
NEXT I
FOR K=3 TO 1000
FOR J=1 TO N
LET A(J)=IN(J)
LET B(J)=IN(J+K)
NEXT J
!LET S1=ABS(CORREL(N,A,B))
LET S2=ABS(RSQ(N,A,B))
LET S3=ABS(PEARSON(N,A,B))
LET S4=ABS(CORR(N,A,B))
IF S2=1 OR S3=1 OR S4=1 THEN PRINT SAMPLINGFREQ/K;"Hz"
NEXT K
END
EXTERNAL FUNCTION CORREL(N,X(),Y())
!'相関係数 -1<=R<=1
LET COV=COVARIANCE(N,X,Y)
LET PX=STDEV(N,X)
LET PY=STDEV(N,Y)
LET CORREL=COV/(PX*PY)
END FUNCTION
EXTERNAL FUNCTION RSQ(N,A(),B())
!'相関係数 0<=R<=1
LET RSQ=PEARSON(N,A,B)^2
END FUNCTION
EXTERNAL FUNCTION PEARSON(N,A(),B())
!'相関係数 -1<=R<=1
FOR I=1 TO N
LET X=X+A(I)
LET XX=XX+A(I)*A(I)
LET Y=Y+B(I)
LET YY=YY+B(I)*B(I)
LET XY=XY+A(I)*B(I)
NEXT I
LET PEARSON=(N*XY-X*Y)/SQR((N*XX-X*X)*(N*YY-Y*Y))
END FUNCTION
EXTERNAL FUNCTION CORR(N,A(),B())
!'相関係数 -1<=R<=1
FOR I=1 TO N
LET XX=XX+A(I)*A(I)
LET YY=YY+B(I)*B(I)
LET XY=XY+A(I)*B(I)
NEXT I
LET CORR=XY/SQR(XX)/SQR(YY)
END FUNCTION
EXTERNAL FUNCTION COVARIANCE(N,X(),Y())
!'共分散
LET NX=MEAN(N,X)
LET NY=MEAN(N,Y)
FOR K=1 TO N
LET S=S+(X(K)-NX)*(Y(K)-NY)
NEXT K
LET COVARIANCE=S/N
END FUNCTION
EXTERNAL FUNCTION STDEV(N,A())
!'標準偏差
FOR I=1 TO N
LET X=X+A(I)
LET XX=XX+A(I)*A(I)
NEXT I
LET STDEV=SQR((N*XX-X*X)/N/(N-1))
END FUNCTION
EXTERNAL FUNCTION MEAN(N,A())
!'相加平均
FOR I=1 TO N
LET X=X+A(I)
NEXT I
LET MEAN=X/N
END FUNCTION
Re: FFTフィルタ処理 - しばっち
2024/10/13 (Sun) 08:04:26
通常FFTを行う場合は実数値なので虚部を0として処理しますが
偶数、奇数に分けることでFFTを半分のサンプル数で行えます。
メモリーの節約にもなります。
LET M=8
LET N=2^M
DIM RR(N),II(N)
FOR I=1 TO N
LET RR(I)=I ! 通常虚部は0とする
LET II(I)=0
NEXT I
CALL FFT(M,RR,II,1)
CALL FFT(M,RR,II,-1)
FOR I=1 TO N
PRINT RR(I);II(I)
NEXT I
MAT RR=ZER
MAT II=ZER
LET M=M-1
LET N=2^M
FOR I=1 TO N
LET RR(I)=2*I-1 ! 偶数、奇数に分ける
LET II(I)=2*I
NEXT I
CALL FFT(M,RR,II,1)
CALL FFT(M,RR,II,-1)
FOR I=1 TO N
PRINT RR(I);II(I)
NEXT I
END
以下略
---------------------------------------------------------------------
LET SAMPLINGFREQ=44100
LET M=10
LET N=2^M
LET LL=SAMPLINGFREQ/N
DIM RR(N),II(N)
FOR I=1 TO N
LET RR(I)=SIN(400/SAMPLINGFREQ*I*2*PI)*.5+SIN(5000/SAMPLINGFREQ*I*2*PI)*.5
LET II(I)=0 ! 通常虚部は0とする
NEXT I
CALL FFT(M,RR,II,1)
SET WINDOW 1,SAMPLINGFREQ/2,-40,70
DRAW GRID(SAMPLINGFREQ/10,10)
FOR I=1 TO N/2
PLOT LINES:I*LL,10*LOG10(RR(I)^2+II(I)^2);
NEXT I
PLOT LINES
MAT RR=ZER
MAT II=ZER
LET N=2^(M-1)
LET LL=SAMPLINGFREQ/N
FOR I=1 TO N
LET RR(I)=SIN(400/SAMPLINGFREQ*(I-1)*2*PI)*.5+SIN(5000/SAMPLINGFREQ*(I-1)*2*PI)*.5
LET II(I)=SIN(400/SAMPLINGFREQ*I*2*PI)*.5+SIN(5000/SAMPLINGFREQ*I*2*PI)*.5 ! 偶数、奇数に分けることで半分のサンプル数でできる
NEXT I
CALL FFT(M-1,RR,II,1)
SET LINE COLOR "RED"
FOR I=1 TO N/2
PLOT LINES:I*LL,10*LOG10(RR(I)^2+II(I)^2);
NEXT I
END
以下略
Re: FFTフィルタ処理 - しばっち
2024/10/13 (Sun) 08:05:53
窓関数
https://ja.wikipedia.org/wiki/窓関数
窓関数はサンプル画像のような山型をしています。
正規化するとグラフの赤線のようになるようです。
https://watlab-blog.com/2019/04/20/window-correction/
LET N=128
FOR X=0 TO N
LET S=S+W(X,N)
NEXT X
LET ACF=1/(S/N)
SET WINDOW -N/20,N,-.1,ACF
DRAW GRID(N/10,.5)
FOR X=0 TO N
PLOT LINES:X,W(X,N);
NEXT X
PLOT LINES
SET LINE COLOR "RED"
FOR X=0 TO N
PLOT LINES:X,W(X,N)*ACF;
NEXT X
PRINT ACF
END
EXTERNAL FUNCTION W(X,N)
LET W=HANNING(X,N)
!LET W=TRIANGULAR(X,N)
!LET W=HAMMING(X,N)
!LET W=BARTLETT(X,N)
!LET W=BARTLETTHANN(X,N)
!LET W=NUTTALL(X,N)
!LET W=BLACKMANHARRIS(X,N)
!LET W=BLACKMANNUTTALL(X,N)
!LET W=FLATTOP(X,N)
!LET W=PARZAN(X)
!LET W=AKAIKE(X,N)
!LET W=WELCH(X,N)
!LET W=SINE(X,N)
!LET W=VORBIS(X,N)
END FUNCTION
EXTERNAL FUNCTION TRIANGULAR(X,N)
LET TRIANGULAR=1-2*ABS((2*X-N)/(2*N))
END FUNCTION
EXTERNAL FUNCTION HANNING(X,N)
LET XX=X/N
LET HANNING=0.5-0.5*COS(2*PI*XX)
END FUNCTION
EXTERNAL FUNCTION HAMMING(X,N)
LET XX=X/N
LET HAMMING=0.54-0.46*COS(2*PI*XX)
END FUNCTION
EXTERNAL FUNCTION BARTLETT(X,N)
LET XX=X/N
LET BARTLETT=1-2*ABS(XX-0.5)
END FUNCTION
EXTERNAL FUNCTION BARTLETTHANN(X,N)
LET XX=X/N
LET BARTLETTHANN=0.62-0.48*ABS(XX-0.5)-0.38*COS(2*PI*XX)
END FUNCTION
EXTERNAL FUNCTION NUTTALL(X,N)
LET XX=X/N
LET NUTTALL=0.355768-0.487396*COS(2*PI*XX)+0.144232*COS(4*PI*XX)-0.012604*COS(6*PI*XX)
END FUNCTION
EXTERNAL FUNCTION BLACKMANHARRIS(X,N)
LET XX=X/N
LET BLACKMANHARRIS=0.35875-0.48829*COS(2*PI*XX)+0.144128*COS(4*PI*XX)-0.01168*COS(6*PI*XX)
END FUNCTION
EXTERNAL FUNCTION BLACKMANNUTTALL(X,N)
LET XX=X/N
LET BLACKMANNUTTALL=0.3635819-0.4891775*COS(2*PI*XX)+0.1365995*COS(4*PI*XX)-0.0106411*COS(6*PI*XX)
END FUNCTION
EXTERNAL FUNCTION FLATTOP(X,N)
LET XX=X/N
LET FLATTOP=1-1.93*COS(2*PI*XX)+1.29*COS(4*PI*XX)+0.388*COS(6*PI*XX)+0.032*COS(8*PI*XX)
END FUNCTION
EXTERNAL FUNCTION PARZAN(X)
IF ABS(X)<=1 THEN
LET PARZAN=1-1.5*X^2+0.75*ABS(X^3)
ELSEIF ABS(X)>1 AND ABS(X)<=2 THEN
LET PARZAN=0.25*(2-ABS(X))^3
END IF
END FUNCTION
EXTERNAL FUNCTION AKAIKE(X,N)
LET XX=X/N
LET AKAIKE=0.625-0.5*COS(2*PI*XX)-0.125*COS(4*PI*XX)
END FUNCTION
EXTERNAL FUNCTION WELCH(X,N)
LET XX=X/N
LET WELCH=4*XX*(1-XX)
END FUNCTION
EXTERNAL FUNCTION SINE(X,N)
LET XX=X/N
LET SINE=SIN(PI*XX)
END FUNCTION
EXTERNAL FUNCTION VORBIS(X,N)
LET XX=X/N
LET VORBIS=SIN(PI/2*SIN(PI*XX)^2)
END FUNCTION
---------------------------------------------------------------------
LET N=1
SET WINDOW 0,N,0,1
FOR B=1 TO 32
FOR X=0 TO N STEP 1/256
LET Y=KAISER(B,X,N)
PLOT LINES:X,Y;
NEXT X
PLOT LINES
NEXT B
END
EXTERNAL FUNCTION BESSEL0(X)
!'I0(X)=Σ(X^M/2^M/M!)^2
LET A=1
LET S=1
FOR M=1 TO 1000
LET A=A*X/M/2
LET S=S+A*A
IF A*A<1E-8 THEN EXIT FOR
NEXT M
LET BESSEL0=S
END FUNCTION
EXTERNAL FUNCTION KAISER(B,X,N) !'カイザー窓
LET KAISER=BESSEL0(B*PI*SQR(1-(2*X/N-1)^2))/BESSEL0(B*PI)
END FUNCTION
---------------------------------------------------------------------
FOR A=.7 TO .1 STEP -1/16
FOR X=0 TO 1 STEP 1/64
LET Y=GAUSS(A,X,1)
PLOT LINES:X,Y;
NEXT X
PLOT LINES
NEXT A
END
EXTERNAL FUNCTION GAUSS(A,Y,N) ! 指数窓
LET X=2*Y-1
LET GAUSS=EXP(-(X/N*X/N)/A/A)
END FUNCTION
Re: FFTフィルタ処理 - しばっち
2024/10/13 (Sun) 08:07:44
wavファイルを読み込んでフィルタ処理を行います。
バッファーサイズを最大2^24(32ビット版十進BASIC)として
サンプリング周波数44100Hzとすると2^24(16777216)/44100=約380秒迄の
PCMデータを読み込みできます。
また高速なFFTライブラリーの移植版を用意しました。
https://www.kurims.kyoto-u.ac.jp/~ooura/fft-j.html
サンプル数2^24個のFFT演算が500秒あまりでした。
※曲の始めは無音状態から始まり徐々に音量が増え(フェードイン)
曲の終わりは徐々に音量が減り(フェードアウト)無音状態で終わるものと想定して
窓関数は使用していません。この想定に反する場合は窓関数を使用してください。
2進モードで実行してください。
LET SIZE=2^24
DIM LIN(SIZE),RIN(SIZE)
DIM LI(SIZE),RI(SIZE)
FILE GETOPENNAME F$,"読み込み WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN,ERR)
IF ERR>0 THEN STOP
LET NN=2^INT(LOG2(NUM)+1) !'FFTポイント数
INPUT PROMPT "ローパス(1) ハイパス(2) バンドパス(3) バンドストップ(4) ":MODE
SELECT CASE MODE
CASE 1
INPUT PROMPT "通過域周波数 0 ~"&STR$(SAMPLINGFREQ/2)&"Hz まで":FREQ1
CASE 2
INPUT PROMPT "遮断域周波数 0 ~"&STR$(SAMPLINGFREQ/2)&"Hz まで":FREQ1
CASE 3
INPUT PROMPT "遮断域周波数 0 ~"&STR$(SAMPLINGFREQ/2)&"Hz まで":FREQ1
INPUT PROMPT "通過域周波数"&STR$(FREQ1)&"~"&STR$(SAMPLINGFREQ/2)&"Hz まで":FREQ2
CASE 4
INPUT PROMPT "通過域周波数 0 ~"&STR$(SAMPLINGFREQ/2)&"Hz まで":FREQ1
INPUT PROMPT "遮断域周波数 "&STR$(FREQ1)&"~"&STR$(SAMPLINGFREQ/2)&"Hz まで":FREQ2
END SELECT
CALL FFTFILTER(MODE,NN,SAMPLINGFREQ,FREQ1,FREQ2,LIN,LI)
IF CHANNEL=2 THEN CALL FFTFILTER(MODE,NN,SAMPLINGFREQ,FREQ1,FREQ2,RIN,RI)
FILE GETSAVENAME F$,"保存 WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL WRITEWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN)
END
EXTERNAL SUB FFTFILTER(MODE,NN,SAMPLINGFREQ,FREQ1,FREQ2,FR(),FI())
CALL CDFT(2*NN,COS(PI/NN),SIN(PI/NN),FR,FI)
SELECT CASE MODE
CASE 1
LET F=FREQ1/SAMPLINGFREQ*NN
FOR I=F TO NN-F
LET FR(I)=0
LET FI(I)=0
NEXT I
CASE 2
LET F=FREQ1/SAMPLINGFREQ*NN
FOR I=1 TO F
LET FR(I)=0
LET FI(I)=0
NEXT I
FOR I=NN-F TO NN
LET FR(I)=0
LET FI(I)=0
NEXT I
CASE 3
LET FS=FREQ1/SAMPLINGFREQ*NN
LET FE=FREQ2/SAMPLINGFREQ*NN
FOR I=1 TO FS
LET FR(I)=0
LET FI(I)=0
NEXT I
FOR I=FE TO NN-FE
LET FR(I)=0
LET FI(I)=0
NEXT I
FOR I=NN-FS TO NN
LET FR(I)=0
LET FI(I)=0
NEXT I
CASE 4
LET FS=FREQ1/SAMPLINGFREQ*NN
LET FE=FREQ2/SAMPLINGFREQ*NN
FOR I=FS TO FE
LET FR(I)=0
LET FI(I)=0
NEXT I
FOR I=NN-FE TO NN-FS
LET FR(I)=0
LET FI(I)=0
NEXT I
END SELECT
CALL CDFT(2*NN,COS(-PI/NN),SIN(-PI/NN),FR,FI)
END SUB
EXTERNAL SUB CDFT(N,WR,WI,AR(),AI())
OPTION BASE 0
DIM A(N)
FOR I=0 TO N/2-1
LET A(2*I)=AR(I+1)
LET A(2*I+1)=AI(I+1)
NEXT I
LET WMR=WR
LET WMI=WI
LET M=N
DO WHILE M>4
LET L=M/2
LET WKR=1
LET WKI=0
LET WDR=1-2*WMI*WMI
LET WDI=2*WMI*WMR
LET SS=2*WDI
LET WMR=WDR
LET WMI=WDI
FOR J=0 TO N-M STEP M
LET I=J+L
LET XR=A(J)-A(I)
LET XI=A(J+1)-A(I+1)
LET A(J)=A(J)+A(I)
LET A(J+1)=A(J+1)+A(I+1)
LET A(I)=XR
LET A(I+1)=XI
LET XR=A(J+2)-A(I+2)
LET XI=A(J+3)-A(I+3)
LET A(J+2)=A(J+2)+A(I+2)
LET A(J+3)=A(J+3)+A(I+3)
LET A(I+2)=WDR*XR-WDI*XI
LET A(I+3)=WDR*XI+WDI*XR
NEXT J
FOR K=4 TO L-4 STEP 4
LET WKR=WKR-SS*WDI
LET WKI=WKI+SS*WDR
LET WDR=WDR-SS*WKI
LET WDI=WDI+SS*WKR
FOR J=K TO N-M+K STEP M
LET I=J+L
LET XR=A(J)-A(I)
LET XI=A(J+1)-A(I+1)
LET A(J)=A(J)+A(I)
LET A(J+1)=A(J+1)+A(I+1)
LET A(I)=WKR*XR-WKI*XI
LET A(I+1)=WKR*XI+WKI*XR
LET XR=A(J+2)-A(I+2)
LET XI=A(J+3)-A(I+3)
LET A(J+2)=A(J+2)+A(I+2)
LET A(J+3)=A(J+3)+A(I+3)
LET A(I+2)=WDR*XR-WDI*XI
LET A(I+3)=WDR*XI+WDI*XR
NEXT J
NEXT K
LET M=L
LOOP
IF M>2 THEN
FOR J=0 TO N-4 STEP 4
LET XR=A(J)-A(J+2)
LET XI=A(J+1)-A(J+3)
LET A(J)=A(J)+A(J+2)
LET A(J+1)=A(J+1)+A(J+3)
LET A(J+2)=XR
LET A(J+3)=XI
NEXT J
END IF
IF N>4 THEN CALL BITRV2(N,A)
FOR I=0 TO N/2-1
LET AR(I+1)=A(2*I)/SQR(N)
LET AI(I+1)=A(2*I+1)/SQR(N)
NEXT I
END SUB
EXTERNAL SUB BITRV2(N,A())
LET M=N/4
LET M2=2*M
LET N2=N-2
LET K=0
FOR J=0 TO M2-4 STEP 4
IF J<K THEN
LET XR=A(J)
LET XI=A(J+1)
LET A(J)=A(K)
LET A(J+1)=A(K+1)
LET A(K)=XR
LET A(K+1)=XI
ELSEIF J>K THEN
LET J1=N2-J
LET K1=N2-K
LET XR=A(J1)
LET XI=A(J1+1)
LET A(J1)=A(K1)
LET A(J1+1)=A(K1+1)
LET A(K1)=XR
LET A(K1+1)=XI
END IF
LET K1=M2+K
LET XR=A(J+2)
LET XI=A(J+3)
LET A(J+2)=A(K1)
LET A(J+3)=A(K1+1)
LET A(K1)=XR
LET A(K1+1)=XI
LET L=M
DO WHILE K>=L
LET K=K-L
LET L=L/2
LOOP
LET K=K+L
NEXT J
END SUB
以下略
---------------------------------------------------------------------------
上記FFTフィルタ処理では全体に対してFFTしていましたが
下記プログラムでは短時間FFT(STFT)によるフィルタ処理しています。
但し、実行結果は上記プログラムとは異なります。
FFTポイント数とFFT実行回数の違いに注目してください。
https://ja.wikipedia.org/wiki/短時間フーリエ変換
LET SIZE=44100*200
DIM LIN(SIZE),RIN(SIZE),LOUT(SIZE),ROUT(SIZE)
FILE GETOPENNAME F$,"読み込み WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN,ERR)
IF ERR>0 THEN STOP
LET NN=2^10 !'FFTポイント数 短時間FFT
LET SFT=NN/8
DIM LR(NN),LI(NN),RR(NN),RI(NN)
INPUT PROMPT "ローパス(1) ハイパス(2) バンドパス(3) バンドストップ(4) ":MODE
SELECT CASE MODE
CASE 1
INPUT PROMPT "通過域周波数 0 ~"&STR$(SAMPLINGFREQ/2)&"Hz まで":FREQ1
CASE 2
INPUT PROMPT "遮断域周波数 0 ~"&STR$(SAMPLINGFREQ/2)&"Hz まで":FREQ1
CASE 3
INPUT PROMPT "遮断域周波数 0 ~"&STR$(SAMPLINGFREQ/2)&"Hz まで":FREQ1
INPUT PROMPT "通過域周波数"&STR$(FREQ1)&"~"&STR$(SAMPLINGFREQ/2)&"Hz まで":FREQ2
CASE 4
INPUT PROMPT "通過域周波数 0 ~"&STR$(SAMPLINGFREQ/2)&"Hz まで":FREQ1
INPUT PROMPT "遮断域周波数 "&STR$(FREQ1)&"~"&STR$(SAMPLINGFREQ/2)&"Hz まで":FREQ2
END SELECT
FOR K=1 TO NUM-NN STEP SFT ! オーバーラップさせる
MAT LI=ZER
MAT RI=ZER
MAT LR=ZER
MAT RR=ZER
FOR J=0 TO NN-1
IF K+J>=1 AND K+J<=NUM THEN
LET LR(J+1)=LIN(K+J)*W(J,NN) ! 窓関数をかける
LET RR(J+1)=RIN(K+J)*W(J,NN)
END IF
NEXT J
CALL FFTFILTER(MODE,NN,SAMPLINGFREQ,FREQ1,FREQ2,LR,LI)
IF CHANNEL=2 THEN CALL FFTFILTER(MODE,NN,SAMPLINGFREQ,FREQ1,FREQ2,RR,RI)
FOR J=0 TO NN-1
LET LOUT(K+J)=LOUT(K+J)+LR(J+1)/4
LET ROUT(K+J)=ROUT(K+J)+RR(J+1)/4
NEXT J
NEXT K
FOR K=1 TO NUM
LET LMAX=MAX(LMAX,ABS(LOUT(K)))
LET RMAX=MAX(RMAX,ABS(ROUT(K)))
NEXT K
MAT LOUT=(1/LMAX)*LOUT
IF CHANNEL=2 THEN MAT ROUT=(1/RMAX)*ROUT
FILE GETSAVENAME F$,"保存 WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL WRITEWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT,ROUT)
END
以下略
---------------------------------------------------------------------------
こちらも短時間FFTによるフィルタ処理です。
LET SIZE=44100*200
DIM LIN(SIZE),RIN(SIZE),LOUT(SIZE),ROUT(SIZE)
FILE GETOPENNAME F$,"読み込み WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN,ERR)
IF ERR>0 THEN STOP
LET NN=256 !'FFTポイント数 短時間FFT
DIM LR(NN),LI(NN),RR(NN),RI(NN)
INPUT PROMPT "ローパス(1) ハイパス(2) バンドパス(3) バンドストップ(4) ":MODE
SELECT CASE MODE
CASE 1
INPUT PROMPT "通過域周波数 0 ~"&STR$(SAMPLINGFREQ/2)&"Hz まで":FREQ1
CASE 2
INPUT PROMPT "遮断域周波数 0 ~"&STR$(SAMPLINGFREQ/2)&"Hz まで":FREQ1
CASE 3
INPUT PROMPT "遮断域周波数 0 ~"&STR$(SAMPLINGFREQ/2)&"Hz まで":FREQ1
INPUT PROMPT "通過域周波数"&STR$(FREQ1)&"~"&STR$(SAMPLINGFREQ/2)&"Hz まで":FREQ2
CASE 4
INPUT PROMPT "通過域周波数 0 ~"&STR$(SAMPLINGFREQ/2)&"Hz まで":FREQ1
INPUT PROMPT "遮断域周波数 "&STR$(FREQ1)&"~"&STR$(SAMPLINGFREQ/2)&"Hz まで":FREQ2
END SELECT
FOR K=1 TO NUM
MAT LI=ZER
MAT RI=ZER
FOR J=-NN/2 TO NN/2-1
IF K+J>=1 AND K+J<=NUM THEN
LET FL=1
LET LR(NN/2+J+1)=LIN(K+J)*W(J+NN/2,NN) ! 窓関数をかける
IF CHANNEL=2 THEN LET RR(NN/2+J+1)=RIN(K+J)*W(J+NN/2,NN)
ELSE
LET FL=0
LET LOUT(K)=LIN(K)
LET ROUT(K)=RIN(K)
EXIT FOR
END IF
NEXT J
IF FL=1 THEN
CALL FFTFILTER(MODE,NN,SAMPLINGFREQ,FREQ1,FREQ2,LR,LI)
LET LOUT(K)=LR(NN/2)
IF CHANNEL=2 THEN
CALL FFTFILTER(MODE,NN,SAMPLINGFREQ,FREQ1,FREQ2,RR,RI)
LET ROUT(K)=RR(NN/2)
END IF
END IF
NEXT K
FILE GETSAVENAME F$,"保存 WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL WRITEWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT,ROUT)
END
以下略
---------------------------------------------------------------------------
アニメーション振幅表示
但し、リアルタイム表示ではありません。
LET SIZE=44100*200
DIM LIN(SIZE),RIN(SIZE)
FILE GETOPENNAME F$,"読み込み WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN,ERR)
IF ERR>0 THEN STOP
LET ST=SAMPLINGFREQ/30 ! 1/30秒毎
LET NN=2^INT(LOG2(ST)+1) !'FFTポイント数
LET JJ=SAMPLINGFREQ/NN ! 分解能
DIM LR(NN),RR(NN),LI(NN),RI(NN)
FOR I=1 TO NUM STEP ST
MAT LI=ZER
MAT RI=ZER
MAT LR=ZER
MAT RR=ZER
FOR J=0 TO ST-1
LET LR(J+1)=LIN(I+J)*W(J,ST) ! 窓関数を掛ける
LET RR(J+1)=RIN(I+J)*W(J,ST)
NEXT J
CALL CDFT(2*NN,COS(PI/NN),SIN(PI/NN),LR,LI)
IF CHANNEL=2 THEN CALL CDFT(2*NN,COS(PI/NN),SIN(PI/NN),RR,RI)
SET VIEWPORT 0,1,0,.49
SET WINDOW 1,SAMPLINGFREQ/2,-50,30
DRAW GRID0(SAMPLINGFREQ/10,10)
FOR J=1 TO NN/2
IF LR(J)<>0 OR LI(J)<>0 THEN
PLOT LINES:J*JJ,-50;J*JJ,10*LOG10(LR(J)^2+LI(J)^2)
END IF
NEXT J
IF CHANNEL=2 THEN
SET VIEWPORT 0,1,.51,1
SET WINDOW 1,SAMPLINGFREQ/2,-50,30
DRAW GRID0(SAMPLINGFREQ/10,10)
FOR J=1 TO NN/2
IF RR(J)<>0 OR RI(J)<>0 THEN
PLOT LINES:J*JJ,-50;J*JJ,10*LOG10(RR(J)^2+RI(J)^2)
END IF
NEXT J
END IF
SET DRAW MODE EXPLICIT
WAIT DELAY .1
SET DRAW MODE HIDDEN
CLEAR
NEXT I
END
以下略
---------------------------------------------------------------------------
スペクトログラム表示
https://ja.wikipedia.org/wiki/スペクトログラム
カラーマップを定義してスペクトログラムを表示します。
サンプル画像参照
LET SIZE=44100*200
DIM LIN(SIZE),RIN(SIZE)
ASK COLOR MIX(15) RED,GREEN,BLUE
CALL JETCOLORMAP
FILE GETOPENNAME F$,"読み込み WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN,ERR)
IF ERR>0 THEN STOP
LET ST=NUM/200
LET NN=2^INT(LOG2(ST)+1)
DIM LR(NN),RR(NN),LI(NN),RI(NN)
LET JJ=SAMPLINGFREQ/NN ! 分解能
LET VMIN=-70 ! db範囲
LET VMAX=0
FOR I=1 TO NUM STEP ST
MAT LI=ZER
MAT RI=ZER
MAT LR=ZER
MAT RR=ZER
FOR J=0 TO ST-1
LET LR(J+1)=LIN(I+J)*W(J,ST) ! 窓関数を掛ける
LET RR(J+1)=RIN(I+J)*W(J,ST)
NEXT J
CALL CDFT(2*NN,COS(PI/NN),SIN(PI/NN),LR,LI)
IF CHANNEL=2 THEN CALL CDFT(2*NN,COS(PI/NN),SIN(PI/NN),RR,RI)
FOR J=1 TO NN/2-1
SET VIEWPORT 0,1,0,.49
SET WINDOW -NUM/20,NUM,-1000,SAMPLINGFREQ/2
IF LR(J)<>0 OR LI(J)<>0 THEN
LET DB=10*LOG10(LR(J)^2+LI(J)^2)
ELSE
LET DB=VMIN
END IF
LET C=INT(INTERPOLATE(DB,VMIN,VMAX,0,255))
SET AREA COLOR C
PLOT AREA:I,J*JJ;I+ST,J*JJ;I+ST,(J+1)*JJ;I,(J+1)*JJ
IF CHANNEL=2 THEN
SET VIEWPORT 0,1,.51,1
SET WINDOW -NUM/20,NUM,-1000,SAMPLINGFREQ/2
IF RR(J)<>0 OR RI(J)<>0 THEN
LET DB=10*LOG10(RR(J)^2+RI(J)^2)
ELSE
LET DB=VMIN
END IF
LET C=INT(INTERPOLATE(DB,VMIN,VMAX,0,255))
SET AREA COLOR C
PLOT AREA:I,J*JJ;I+ST,J*JJ;I+ST,(J+1)*JJ;I,(J+1)*JJ
END IF
NEXT J
NEXT I
SET COLOR MIX(15) RED,GREEN,BLUE
SET VIEWPORT 0,1,0,.49
SET WINDOW -NUM/20/SAMPLINGFREQ,NUM/SAMPLINGFREQ,-1000,SAMPLINGFREQ/2
DRAW GRID(NUM/10/SAMPLINGFREQ,5000)
SET VIEWPORT 0,1,.51,1
SET WINDOW -NUM/20/SAMPLINGFREQ,NUM/SAMPLINGFREQ,-1000,SAMPLINGFREQ/2
DRAW GRID(NUM/10/SAMPLINGFREQ,5000)
END
EXTERNAL FUNCTION INTERPOLATE(X,XMIN,XMAX,YMIN,YMAX) ! XMIN<=X<=XMAX → YMIN(0)~YMAX(255)
LET X=MIN(XMAX,MAX(X,XMIN))
LET INTERPOLATE=(X-XMIN)*(YMAX-YMIN)/(XMAX-XMIN) + YMIN
END FUNCTION
以下略
---------------------------------------------------------------------------
3バンドグラフィックイコライザー
低音域、中音域、高音域でイコライジング処理をします。
上記想定により窓関数は使用していません。
LET SIZE=2^23
DIM LIN(SIZE),RIN(SIZE)
DIM LI(SIZE),RI(SIZE)
FILE GETOPENNAME F$,"読み込み WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN,ERR)
IF ERR>0 THEN STOP
LET NN=2^INT(LOG2(NUM)+1) !'FFTポイント数
INPUT PROMPT "低音 db=":DB
LET GAIN1=10^(DB/20)
INPUT PROMPT "中音 db=":DB
LET GAIN2=10^(DB/20)
INPUT PROMPT "高音 db=":DB
LET GAIN3=10^(DB/20)
CALL FFTFILTER(NN,SAMPLINGFREQ,SAMPLINGFREQ/12,SAMPLINGFREQ*3/12,SAMPLINGFREQ*5/12,SAMPLINGFREQ/12,GAIN1,GAIN2,GAIN3,LIN,LI)
IF CHANNEL=2 THEN CALL FFTFILTER(NN,SAMPLINGFREQ,SAMPLINGFREQ/12,SAMPLINGFREQ*3/12,SAMPLINGFREQ*5/12,SAMPLINGFREQ/12,GAIN1,GAIN2,GAIN3,RIN,RI)
FILE GETSAVENAME F$,"保存 WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL WRITEWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN)
END
EXTERNAL SUB FFTFILTER(NN,SAMPLINGFREQ,FREQ1,FREQ2,FREQ3,WIDTH,GAIN1,GAIN2,GAIN3,FR(),FI())
CALL CDFT(2*NN,COS(PI/NN),SIN(PI/NN),FR,FI)
IF FREQ1<SAMPLINGFREQ/2 THEN
LET F=FREQ1/SAMPLINGFREQ*NN
LET FS=F-WIDTH
LET FE=F+WIDTH
IF FS<0 THEN LET FS=0
IF FE>SAMPLINGFREQ/2*NN THEN LET FE=SAMPLINGFREQ/2*NN
FOR I=FS TO FE
LET FR(I)=FR(I)*GAIN1
NEXT I
FOR I=NN-FE TO NN-FS
LET FR(I)=FR(I)*GAIN1
NEXT I
END IF
IF FREQ2<SAMPLINGFREQ/2 THEN
LET F=FREQ2/SAMPLINGFREQ*NN
LET FS=F-WIDTH
LET FE=F+WIDTH
IF FS<0 THEN LET FS=0
IF FE>SAMPLINGFREQ/2*NN THEN LET FE=SAMPLINGFREQ/2*NN
FOR I=FS TO FE
LET FR(I)=FR(I)*GAIN2
NEXT I
FOR I=NN-FE TO NN-FS
LET FR(I)=FR(I)*GAIN2
NEXT I
END IF
IF FREQ3<SAMPLINGFREQ/2 THEN
LET F=FREQ3/SAMPLINGFREQ*NN
LET FS=F-WIDTH
LET FE=F+WIDTH
IF FS<0 THEN LET FS=0
IF FE>SAMPLINGFREQ/2*NN THEN LET FE=SAMPLINGFREQ/2*NN
FOR I=FS TO FE
LET FR(I)=FR(I)*GAIN3
NEXT I
FOR I=NN-FE TO NN-FS
LET FR(I)=FR(I)*GAIN3
NEXT I
END IF
CALL CDFT(2*NN,COS(-PI/NN),SIN(-PI/NN),FR,FI)
END SUB
以下略
---------------------------------------------------------------------------
8バンドグラフィックイコライザー
100Hz,200Hz,400Hz,800Hz,1600Hz,3200Hz,6400Hz,12800Hz付近の増減によるイコライジング処理をします。
※6400Hzはサンプリング周波数16000Hz以上、12800Hzはサンプリング周波数32000Hz以上の時に有効です。
上記想定により窓関数は使用していません。
LET SIZE=2^23
DIM LIN(SIZE),RIN(SIZE)
DIM LI(SIZE),RI(SIZE)
FILE GETOPENNAME F$,"読み込み WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN,ERR)
IF ERR>0 THEN STOP
LET NN=2^INT(LOG2(NUM)+1) !'FFTポイント数
INPUT PROMPT "100Hz db=":DB ! -10db~10db
LET GAIN1=10^(DB/20)
INPUT PROMPT "200Hz db=":DB
LET GAIN2=10^(DB/20)
INPUT PROMPT "400Hz db=":DB
LET GAIN3=10^(DB/20)
INPUT PROMPT "800Hz db=":DB
LET GAIN4=10^(DB/20)
INPUT PROMPT "1600Hz db=":DB
LET GAIN5=10^(DB/20)
INPUT PROMPT "3200Hz db=":DB
LET GAIN6=10^(DB/20)
IF SAMPLINGFREQ>=16000 THEN
INPUT PROMPT "6400Hz db=":DB
LET GAIN7=10^(DB/20)
IF SAMPLINGFREQ>=32000 THEN
INPUT PROMPT "12800Hz db=":DB
LET GAIN8=10^(DB/20)
END IF
END IF
CALL FFTFILTER(NN,SAMPLINGFREQ,100,200,400,800,1600,3200,6400,12800,GAIN1,GAIN2,GAIN3,GAIN4,GAIN5,GAIN6,GAIN7,GAIN8,LIN,LI)
IF CHANNEL=2 THEN CALL FFTFILTER(NN,SAMPLINGFREQ,100,200,400,800,1600,3200,6400,12800,GAIN1,GAIN2,GAIN3,GAIN4,GAIN5,GAIN6,GAIN7,GAIN8,RIN,RI)
FILE GETSAVENAME F$,"保存 WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL WRITEWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN)
END
EXTERNAL SUB FFTFILTER(NN,SAMPLINGFREQ,FREQ1,FREQ2,FREQ3,FREQ4,FREQ5,FREQ6,FREQ7,FREQ8,GAIN1,GAIN2,GAIN3,GAIN4,GAIN5,GAIN6,GAIN7,GAIN8,FR(),FI())
CALL CDFT(2*NN,COS(PI/NN),SIN(PI/NN),FR,FI)
IF FREQ1<SAMPLINGFREQ/2 THEN
LET F=FREQ1/SAMPLINGFREQ*NN
LET FS=F-1
LET FE=F+1
FOR I=FS TO FE
LET FR(I)=FR(I)*GAIN1
NEXT I
FOR I=NN-FE TO NN-FS
LET FR(I)=FR(I)*GAIN1
NEXT I
END IF
IF FREQ2<SAMPLINGFREQ/2 THEN
LET F=FREQ2/SAMPLINGFREQ*NN
LET FS=F-1
LET FE=F+1
FOR I=FS TO FE
LET FR(I)=FR(I)*GAIN2
NEXT I
FOR I=NN-FE TO NN-FS
LET FR(I)=FR(I)*GAIN2
NEXT I
END IF
IF FREQ3<SAMPLINGFREQ/2 THEN
LET F=FREQ3/SAMPLINGFREQ*NN
LET FS=F-1
LET FE=F+1
FOR I=FS TO FE
LET FR(I)=FR(I)*GAIN3
NEXT I
FOR I=NN-FE TO NN-FS
LET FR(I)=FR(I)*GAIN3
NEXT I
END IF
IF FREQ4<SAMPLINGFREQ/2 THEN
LET F=FREQ4/SAMPLINGFREQ*NN
LET FS=F-1
LET FE=F+1
FOR I=FS TO FE
LET FR(I)=FR(I)*GAIN4
NEXT I
FOR I=NN-FE TO NN-FS
LET FR(I)=FR(I)*GAIN4
NEXT I
END IF
IF FREQ5<SAMPLINGFREQ/2 THEN
LET F=FREQ5/SAMPLINGFREQ*NN
LET FS=F-1
LET FE=F+1
FOR I=FS TO FE
LET FR(I)=FR(I)*GAIN5
NEXT I
FOR I=NN-FE TO NN-FS
LET FR(I)=FR(I)*GAIN5
NEXT I
END IF
IF FREQ6<SAMPLINGFREQ/2 THEN
LET F=FREQ6/SAMPLINGFREQ*NN
LET FS=F-1
LET FE=F+1
FOR I=FS TO FE
LET FR(I)=FR(I)*GAIN6
NEXT I
FOR I=NN-FE TO NN-FS
LET FR(I)=FR(I)*GAIN6
NEXT I
END IF
IF FREQ7<SAMPLINGFREQ/2 THEN
LET F=FREQ7/SAMPLINGFREQ*NN
LET FS=F-1
LET FE=F+1
FOR I=FS TO FE
LET FR(I)=FR(I)*GAIN7
NEXT I
FOR I=NN-FE TO NN-FS
LET FR(I)=FR(I)*GAIN7
NEXT I
END IF
IF FREQ8<SAMPLINGFREQ/2 THEN
LET F=FREQ8/SAMPLINGFREQ*NN
LET FS=F-1
LET FE=F+1
FOR I=FS TO FE
LET FR(I)=FR(I)*GAIN8
NEXT I
FOR I=NN-FE TO NN-FS
LET FR(I)=FR(I)*GAIN8
NEXT I
END IF
CALL CDFT(2*NN,COS(-PI/NN),SIN(-PI/NN),FR,FI)
END SUB
以下略
---------------------------------------------------------------------------
パラメトリックイコライザー
中心周波数からバンド幅域内の周波数帯を増減させます。
上記想定により窓関数は使用していません。
LET SIZE=2^23
DIM LIN(SIZE),RIN(SIZE)
DIM LI(SIZE),RI(SIZE)
FILE GETOPENNAME F$,"読み込み WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN,ERR)
IF ERR>0 THEN STOP
LET NN=2^INT(LOG2(NUM)+1) !'FFTポイント数
INPUT PROMPT "中心周波数 (0~"&STR$(SAMPLINGFREQ/2)&")=":FREQ
INPUT PROMPT "バンド幅(0~"&STR$(SAMPLINGFREQ/4)&")=":WIDTH
INPUT PROMPT "増幅率(-10~10)=":DB
LET GAIN=10^(DB/20)
CALL FFTFILTER(NN,SAMPLINGFREQ,FREQ,WIDTH,GAIN,LIN,LI)
IF CHANNEL=2 THEN CALL FFTFILTER(NN,SAMPLINGFREQ,FREQ,WIDTH,GAIN,RIN,RI)
FILE GETSAVENAME F$,"保存 WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL WRITEWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,16,LIN,RIN)
END
EXTERNAL SUB FFTFILTER(N,SAMPLINGFREQ,FREQ,WIDTH,GAIN,RR(),II()) ! パラメトリックEQ
CALL CDFT(2*N,COS(PI/N),SIN(PI/N),RR,II)
LET FS=(FREQ-WIDTH/2)/SAMPLINGFREQ*N
LET FE=(FREQ+WIDTH/2)/SAMPLINGFREQ*N
IF FS<0 THEN LET FS=0
IF FE>SAMPLINGFREQ/2*N THEN LET FE=SAMPLINGFREQ/2*N
FOR I=FS TO FE
LET RR(I)=RR(I)*GAIN
NEXT I
FOR I=N-FE TO N-FS
LET RR(I)=RR(I)*GAIN
NEXT I
CALL CDFT(2*N,COS(-PI/N),SIN(-PI/N),RR,II)
END SUB
以下略
---------------------------------------------------------------
16バンドグラフィックイコライザー
LET SIZE=44100*200
LET NN=1024 !'FFTポイント数
LET SFT=NN/8
LET M=16
DIM LIN(SIZE),RIN(SIZE),LOUT(SIZE),ROUT(SIZE)
DIM LR(NN),LI(NN),RR(NN),RI(NN),FREQ(M),GAIN(M)
FILE GETOPENNAME F$,"読み込み WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN,ERR)
IF ERR>0 THEN STOP
FOR K=1 TO M
READ FREQ(K)
IF FREQ(K)<SAMPLINGFREQ/2 THEN
INPUT PROMPT STR$(FREQ(K))&"Hz db=":DB
LET GAIN(K)=10^(DB/20)
END IF
NEXT K
FOR K=1 TO NUM-NN STEP SFT
MAT LI=ZER
MAT RI=ZER
MAT LR=ZER
MAT RR=ZER
FOR J=0 TO NN-1
LET LR(J+1)=LIN(K+J)*W(J,NN) ! 窓関数を掛ける
LET RR(J+1)=RIN(K+J)*W(J,NN)
NEXT J
CALL FFTFILTER(NN,SAMPLINGFREQ,FREQ,GAIN,M,LR,LI)
IF CHANNEL=2 THEN CALL FFTFILTER(NN,SAMPLINGFREQ,FREQ,GAIN,M,RR,RI)
FOR J=0 TO NN-1
LET LOUT(K+J)=LOUT(K+J)+LR(J+1)/4
LET ROUT(K+J)=ROUT(K+J)+RR(J+1)/4
NEXT J
NEXT K
FOR K=1 TO NUM
LET LMAX=MAX(LMAX,ABS(LOUT(K)))
LET RMAX=MAX(RMAX,ABS(ROUT(K)))
NEXT K
MAT LOUT=(1/LMAX)*LOUT
IF CHANNEL=2 THEN MAT ROUT=(1/RMAX)*ROUT
FILE GETSAVENAME F$,"保存 WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL WRITEWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN)
DATA 50,100,200,400,600,800,1000,1200,1600,2000,2500,3000,4000,8000,12000,16000
END
EXTERNAL SUB FFTFILTER(NN,SAMPLINGFREQ,FREQ(),GAIN(),M,FR(),FI())
CALL CDFT(2*NN,COS(PI/NN),SIN(PI/NN),FR,FI)
FOR K=1 TO M
IF FREQ(K)<SAMPLINGFREQ/2 THEN
LET F=FREQ(K)/SAMPLINGFREQ*NN
LET FS=F-1
LET FE=F+1
FOR I=FS TO FE
LET FR(I)=FR(I)*GAIN(K)
NEXT I
FOR I=NN-FE TO NN-FS
LET FR(I)=FR(I)*GAIN(K)
NEXT I
END IF
NEXT K
CALL CDFT(2*NN,COS(-PI/NN),SIN(-PI/NN),FR,FI)
END SUB
以下略
---------------------------------------------------------------
ヘリウムボイス(ドナルドダック効果、ボイスチェンジャー)
https://nettyukobo.com/helium_voice/
https://ja.wikipedia.org/wiki/音速
https://www.balloonworld.jp/column/voice/
OPTION BASE 0
LET SIZE=44100*200
DIM LIN(SIZE),RIN(SIZE),LOUT(SIZE),ROUT(SIZE)
FILE GETOPENNAME F$,"読み込み WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN,ERR)
IF ERR>0 THEN STOP
LET NN=2^10 !'FFTポイント数 短時間FFT
LET SFT=NN/8
LET LL=26
LET EPS=1E-15
! 音速(1気圧0度) 空気=331m/s 水素=1269m/s ヘリウム=970m/s 窒素=337m/s 酸素=317m/s 塩素=205m/s アルゴン=319m/s 二酸化炭素=258m/s
LET RATE=2 ! 空気中の音速との速度比 ヘリウム/空気=2.93 水素/空気=3.83 塩素/空気=0.61 二酸化炭素/空気=0.77
DIM LR(NN),LI(NN),RR(NN),RI(NN),LLOG(NN),RLOG(NN),LTMP(NN),RTMP(NN)
DIM LCL(NN),LCH(NN),RCL(NN),RCH(NN),L(NN),R(NN),LAMP(NN),RAMP(NN)
FOR K=1 TO NUM-NN STEP SFT
MAT LI=ZER
MAT RI=ZER
MAT LR=ZER
MAT RR=ZER
FOR J=0 TO NN-1
IF K+J>=1 AND K+J<=NUM THEN
LET LR(J+1)=LIN(K+J)*W(J,NN) ! 窓関数をかける
LET RR(J+1)=RIN(K+J)*W(J,NN)
END IF
NEXT J
CALL CDFT(2*NN,COS(PI/NN),SIN(PI/NN),LR,LI)
IF CHANNEL=2 THEN CALL CDFT(2*NN,COS(PI/NN),SIN(PI/NN),RR,RI)
FOR I=1 TO NN
LET LLOG(I)=LOG(SQR(LR(I)^2+LI(I)^2)+EPS)
IF CHANNEL=2 THEN LET RLOG(I)=LOG(SQR(RR(I)^2+RI(I)^2)+EPS)
NEXT I
FOR I=1 TO NN
IF LR(I)=0 AND LI(I)=0 THEN LET LI(I)=0 ELSE LET LI(I)=ANGLE(LR(I),LI(I))
IF RR(I)=0 AND RI(I)=0 THEN LET RI(I)=0 ELSE LET RI(I)=ANGLE(RR(I),RI(I))
NEXT I
MAT LTMP=ZER
MAT RTMP=ZER
CALL CDFT(2*NN,COS(-PI/NN),SIN(-PI/NN),LLOG,LTMP)
IF CHANNEL=2 THEN CALL CDFT(2*NN,COS(-PI/NN),SIN(-PI/NN),RLOG,RTMP)
MAT LCL=LLOG
MAT LCH=LLOG
MAT RCL=RLOG
MAT RCH=RLOG
FOR I=LL TO NN-LL
LET LCL(I)=0
LET RCL(I)=0
NEXT I
FOR I=1 TO LL
LET LCH(I)=0
LET RCH(I)=0
NEXT I
FOR I=NN-LL TO NN
LET LCH(I)=0
LET RCH(I)=0
NEXT I
MAT LTMP=ZER
CALL CDFT(2*NN,COS(PI/NN),SIN(PI/NN),LCL,LTMP)
MAT LTMP=ZER
CALL CDFT(2*NN,COS(PI/NN),SIN(PI/NN),LCH,LTMP)
IF CHANNEL=2 THEN
MAT RTMP=ZER
CALL CDFT(2*NN,COS(PI/NN),SIN(PI/NN),RCL,RTMP)
MAT RTMP=ZER
CALL CDFT(2*NN,COS(PI/NN),SIN(PI/NN),RCH,RTMP)
END IF
MAT LAMP=(-1000)*CON
MAT RAMP=(-1000)*CON
FOR I=1 TO NN/2
LET CN=IP(I/RATE)
LET CR=FP(I/RATE)
IF CN<NN/2 THEN
LET LAMP(I)=(1-CR)*LCL(CN)+CR*LCL(CN+1)
LET RAMP(I)=(1-CR)*RCL(CN)+CR*RCL(CN+1)
END IF
NEXT I
FOR I=1 TO NN
LET L(I)=EXP(LAMP(I)+LCH(I))
LET R(I)=EXP(RAMP(I)+RCH(I))
NEXT I
FOR I=1 TO NN
LET LI(I)=L(I)*SIN(LI(I))
LET L(I)=L(I)*COS(L(I))
LET RI(I)=R(I)*SIN(RI(I))
LET R(I)=R(I)*COS(R(I))
NEXT I
CALL CDFT(2*NN,COS(-PI/NN),SIN(-PI/NN),L,LI)
IF CHANNEL=2 THEN CALL CDFT(2*NN,COS(-PI/NN),SIN(-PI/NN),R,RI)
FOR J=0 TO NN-1
LET LOUT(K+J)=LOUT(K+J)+L(J+1)/4
LET ROUT(K+J)=ROUT(K+J)+R(J+1)/4
NEXT J
NEXT K
FOR K=1 TO NUM
LET LMAX=MAX(LMAX,ABS(LOUT(K)))
LET RMAX=MAX(RMAX,ABS(ROUT(K)))
NEXT K
MAT LOUT=(1/LMAX)*LOUT
IF CHANNEL=2 THEN MAT ROUT=(1/RMAX)*ROUT
FILE GETSAVENAME F$,"保存 WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL WRITEWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT,ROUT)
END
以下略
Re: FFTフィルタ処理 - しばっち
2024/10/13 (Sun) 08:09:40
高速なFFTライブラリーFFTWを使用したFFTルーチンも用意した。
https://www.fftw.org/
VC++2022でコンパイルしました。32bit版のみです。
実行には別途libfftw3-3.dllが必要です。
サンプル数2^24個のFFT演算が約2分程でした。
LET N=2^20
DIM RR(N),II(N)
FOR I=1 TO N
LET RR(I)=I
LET II(I)=0
NEXT I
CALL FFTW(N,RR,II,0) ! FFT
FOR I=1 TO 100
PRINT RR(I);II(I)
NEXT I
CALL FFTW(N,RR,II,1) ! IFFT
FOR I=1 TO 100
PRINT RR(I);II(I)
NEXT I
END
EXTERNAL SUB FFTW(N,RR(),II(),SW)
OPTION CHARACTER BYTE
LET RE$=REPEAT$(CHR$(0),N*8)
LET IM$=REPEAT$(CHR$(0),N*8)
FOR I=0 TO N-1
LET RE$(8*I+1:8*I+8)=PACKDBL$(RR(I+1)) !'実部
LET IM$(8*I+1:8*I+8)=PACKDBL$(II(I+1)) !'虚部
NEXT I
CALL FFTW_(N,RE$,IM$,SW)
FOR I=0 TO N-1
LET RR(I+1)=UNPACKDBL(RE$(8*I+1:8*I+8))
LET II(I+1)=UNPACKDBL(IM$(8*I+1:8*I+8))
IF SW<>0 THEN
LET RR(I+1)=RR(I+1)/N
LET II(I+1)=II(I+1)/N
END IF
NEXT I
SUB FFTW_(N,RE$,IM$,SW) ! SW=0...FFT SW<>0...IFFT
OPTION CHARACTER BYTE
ASSIGN ".\DLL\fftw.dll","fftwsub"
END SUB
END SUB
-----------------------------------------------------------------------
fftw.c
#include <stdio.h>
#include <stdlib.h>
#include <complex.h>
#include <fftw3.h>
__declspec(dllexport) void fftwsub(int n,double *re,double *im,int sw)
{
int i;
fftw_complex *a, *b;
a = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * n);
b = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * n);
if (a==NULL || b==NULL) exit(1);
fftw_plan plan;
for (i=0; i<n; i++)
{
a[i][0]=re[i];
a[i][1]=im[i];
}
if (sw==0)
{
plan = fftw_plan_dft_1d( n, a, b, FFTW_FORWARD, FFTW_ESTIMATE);
}
else
{
plan = fftw_plan_dft_1d( n, a, b, FFTW_BACKWARD, FFTW_ESTIMATE);
}
fftw_execute(plan);
for (i=0; i<n; i++) {
re[i]=b[i][0];
im[i]=b[i][1];
}
if(plan) fftw_destroy_plan(plan);
fftw_free(a);
fftw_free(b);
}
Re: FFTフィルタ処理 - しばっち
2024/10/13 (Sun) 08:11:08
高速なfftライブラリーによるfftルーチン
https://www.kurims.kyoto-u.ac.jp/~ooura/fft-j.html
VC++2022でコンパイルしました。32bit版のみです。
サンプル数2^24個のFFT演算が100秒あまりでした。
LET N=2^16
DIM RR(N),II(N)
FOR I=1 TO N
LET RR(I)=I
LET II(I)=0
NEXT I
CALL CDFT(N,RR,II,1) ! FFT
FOR I=1 TO 100
PRINT RR(I);II(I)
NEXT I
CALL CDFT(N,RR,II,-1) ! IFFT
FOR I=1 TO 100
PRINT RR(I);II(I)
NEXT I
END
EXTERNAL SUB CDFT(N,RR(),II(),SW)
OPTION CHARACTER BYTE
LET A$=REPEAT$(CHR$(0),N*8*2)
LET IP$=REPEAT$(CHR$(0),(2+SQR(N))*4)
LET W$=REPEAT$(CHR$(0),N/2*8)
FOR I=0 TO N-1
LET A$(2*8*I+1:2*8*I+8)=PACKDBL$(RR(I+1)) !RE
LET A$(2*8*I+9:2*8*I+16)=PACKDBL$(II(I+1)) !IM
NEXT I
CALL CDFT_(2*N,SW,A$,IP$,W$) ! SW=1...FFT SW=-1...IFFT
FOR I=0 TO N-1
LET RR(I+1)=UNPACKDBL(A$(2*8*I+1:2*8*I+8))
LET II(I+1)=UNPACKDBL(A$(2*8*I+9:2*8*I+16))
IF SW=-1 THEN
LET RR(I+1)=RR(I+1)/N
LET II(I+1)=II(I+1)/N
END IF
NEXT I
SUB CDFT_(N,ISGN,A$,IP$,W$)
IF BITAND(N,N-1)<>0 THEN STOP
ASSIGN ".\DLL\fftsg.dll","cdft"
END SUB
!SUB CDFT_(N,ISGN,A$,IP$,W$)
! IF BITAND(N,N-1)<>0 THEN STOP
! ASSIGN ".\DLL\fft8g.dll","cdft"
!END SUB
!SUB CDFT(N,ISGN,A$,IP$,W$)
! OPTION CHARACTER BYTE
! IF BITAND(N,N-1)<>0 THEN STOP
! ASSIGN ".\DLL\fft4g.dll","cdft"
!END SUB
END SUB
----------------------------------------------------------------------------
fftsg.c
__declspec(dllexport) void cdft(int n, int isgn, double *a, int *ip, double *w)
{
void makewt(int nw, int *ip, double *w);
void cftfsub(int n, double *a, int *ip, int nw, double *w);
void cftbsub(int n, double *a, int *ip, int nw, double *w);
int nw;
nw = ip[0];
if (n > (nw << 2)) {
nw = n >> 2;
makewt(nw, ip, w);
}
if (isgn >= 0) {
cftfsub(n, a, ip, nw, w);
} else {
cftbsub(n, a, ip, nw, w);
}
}
以下略
Re: FFTフィルタ処理 - しばっち
2024/10/13 (Sun) 08:12:29
cによるDFTのDLL版です。OPENMPのマルチスレッド化による力技で高速化しています。(※CPU使用率が100%になります)
数千個程度なら個数Nに制約なしで実行できます。
VC++2022でコンパイルしました。32bit版のみです。
実行にはVCのOPEN MPランタイムvcomp140.dllが別途必要です。
EXTERNAL SUB DFT(N,RR(),II())
OPTION CHARACTER BYTE
LET AR$=REPEAT$(CHR$(0),N*8)
LET AI$=REPEAT$(CHR$(0),N*8)
FOR I=0 TO N-1
LET AR$(8*I+1:8*I+8)=PACKDBL$(RR(I+1)) !RE
LET AI$(8*I+1:8*I+8)=PACKDBL$(II(I+1)) !IM
NEXT I
CALL DFT_(N,AR$,AI$)
FOR I=0 TO N-1
LET RR(I+1)=UNPACKDBL(AR$(8*I+1:8*I+8))
LET II(I+1)=UNPACKDBL(AI$(8*I+1:8*I+8))
NEXT I
SUB DFT_(N,AR$,AI$)
OPTION CHARACTER BYTE
ASSIGN ".\DLL\dft.dll","dft"
END SUB
END SUB
EXTERNAL SUB IDFT(N,RR(),II())
OPTION CHARACTER BYTE
LET AR$=REPEAT$(CHR$(0),N*8)
LET AI$=REPEAT$(CHR$(0),N*8)
FOR I=0 TO N-1
LET AR$(8*I+1:8*I+8)=PACKDBL$(RR(I+1)) !RE
LET AI$(8*I+1:8*I+8)=PACKDBL$(II(I+1)) !IM
NEXT I
CALL IDFT_(N,AR$,AI$)
FOR I=0 TO N-1
LET RR(I+1)=UNPACKDBL(AR$(8*I+1:8*I+8))
LET II(I+1)=UNPACKDBL(AI$(8*I+1:8*I+8))
NEXT I
SUB IDFT_(N,AR$,AI$)
ASSIGN ".\DLL\dft.dll","idft"
END SUB
END SUB
!EXTERNAL SUB DFT2D(M,N,AR(,),AI(,),SW) ! SW=1...DFT SW=-1...IDFT
!OPTION CHARACTER BYTE
!LET AR$=REPEAT$(CHR$(0),M*N*8)
!LET AI$=REPEAT$(CHR$(0),M*N*8)
!FOR J=0 TO N-1
! FOR I=0 TO M-1
! LET AR$(8*(J*M+I)+1:8*(J*M+I)+8)=PACKDBL$(AR(I+1,J+1))
! LET AI$(8*(J*M+I)+1:8*(J*M+I)+8)=PACKDBL$(AI(I+1,J+1))
! NEXT I
!NEXT J
!CALL DFT2(M,N,SW,AR$,AI$)
!FOR J=0 TO N-1
! FOR I=0 TO M-1
! LET AR(I+1,J+1)=UNPACKDBL(AR$(8*(J*M+I)+1:8*(J*M+I)+8))
! LET AI(I+1,J+1)=UNPACKDBL(AI$(8*(J*M+I)+1:8*(J*M+I)+8))
! NEXT I
!NEXT J
!
!SUB DFT2(M,N,FLAG,AR$,AI$)
! ASSIGN ".\DLL\dft.dll","dft2"
!END SUB
!END SUB
!EXTERNAL SUB DFT2D(M,N,AR(,),AI(,))
!OPTION CHARACTER BYTE
!LET AR$=REPEAT$(CHR$(0),M*8)
!LET AI$=REPEAT$(CHR$(0),M*8)
!FOR J=0 TO N-1
! FOR I=0 TO M-1
! LET AR$(8*I+1:8*I+8)=PACKDBL$(AR(I,J))
! LET AI$(8*I+1:8*I+8)=PACKDBL$(AI(I,J))
! NEXT I
! CALL DFT(M,AR$,AI$)
! FOR I=0 TO M-1
! LET AR(I,J)=UNPACKDBL(AR$(8*I+1:8*I+8))
! LET AI(I,J)=UNPACKDBL(AI$(8*I+1:8*I+8))
! NEXT I
!NEXT J
!LET AR$=REPEAT$(CHR$(0),N*8)
!LET AI$=REPEAT$(CHR$(0),N*8)
!FOR J=0 TO M-1
! FOR I=0 TO N-1
! LET AR$(8*I+1:8*I+8)=PACKDBL$(AR(J,I))
! LET AI$(8*I+1:8*I+8)=PACKDBL$(AI(J,I))
! NEXT I
! CALL DFT(N,AR$,AI$)
! FOR I=0 TO N-1
! LET AR(J,I)=UNPACKDBL(AR$(8*I+1:8*I+8))
! LET AI(J,I)=UNPACKDBL(AI$(8*I+1:8*I+8))
! NEXT I
!NEXT J
!END SUB
!EXTERNAL SUB IDFT2D(M,N,AR(,),AI(,))
!OPTION CHARACTER BYTE
!LET AR$=REPEAT$(CHR$(0),M*8)
!LET AI$=REPEAT$(CHR$(0),M*8)
!FOR J=0 TO N-1
! FOR I=0 TO M-1
! LET AR$(8*I+1:8*I+8)=PACKDBL$(AR(I,J))
! LET AI$(8*I+1:8*I+8)=PACKDBL$(AI(I,J))
! NEXT I
! CALL IDFT(M,AR$,AI$)
! FOR I=0 TO M-1
! LET AR(I,J)=UNPACKDBL(AR$(8*I+1:8*I+8))
! LET AI(I,J)=UNPACKDBL(AI$(8*I+1:8*I+8))
! NEXT I
!NEXT J
!LET AR$=REPEAT$(CHR$(0),N*8)
!LET AI$=REPEAT$(CHR$(0),N*8)
!FOR J=0 TO M-1
! FOR I=0 TO N-1
! LET AR$(8*I+1:8*I+8)=PACKDBL$(AR(J,I))
! LET AI$(8*I+1:8*I+8)=PACKDBL$(AI(J,I))
! NEXT I
! CALL IDFT(N,AR$,AI$)
! FOR I=0 TO N-1
! LET AR(J,I)=UNPACKDBL(AR$(8*I+1:8*I+8))
! LET AI(J,I)=UNPACKDBL(AI$(8*I+1:8*I+8))
! NEXT I
!NEXT J
!END SUB
------------------------------------------------------------------------------
dft.c
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
#define PI 3.14159265358979323846
__declspec(dllexport) void dft(int m, double *xr, double *xi)
{
double *rr,*ii;
double p;
int i,j;
rr = malloc(m * sizeof(double));
ii = malloc(m * sizeof(double));
if (rr == NULL || ii == NULL) exit(1);
#pragma omp parallel for
for (i=0; i<m; i++) {
rr[i]=0;
ii[i]=0;
}
p = 2*PI/(double)m;
#pragma omp parallel for private(i,j)
for (j=0; j<m; j++) {
for (i=0; i<m; i++) {
rr[j] += xr[i] * cos(p * j * i) - xi[i] * sin(p * j * i);
ii[j] += xr[i] * sin(p * j * i) + xi[i] * cos(p * j * i);
}
}
#pragma omp parallel for
for(i = 0; i<m; i++) {
xr[i] = rr[i];
xi[i] = ii[i];
}
free(rr);
free(ii);
}
__declspec(dllexport) void idft(int m, double *xr, double *xi)
{
double *rr,*ii;
double p;
int i,j;
rr = malloc(m * sizeof(double));
ii = malloc(m * sizeof(double));
if (rr == NULL || ii == NULL) exit(1);
p = 2*PI/(double)m;
#pragma omp parallel for
for (i=0; i<m; i++) {
rr[i]=0;
ii[i]=0;
}
#pragma omp parallel for private(i,j)
for (j=0; j<m; j++) {
for (i=0; i<m; i++) {
rr[j] += xr[i] * cos(-p * j * i) - xi[i] * sin(-p * j * i);
ii[j] += xr[i] * sin(-p * j * i) + xi[i] * cos(-p * j * i);
}
}
#pragma omp parallel for
for(i = 0; i<m; i++) {
xr[i] = rr[i]/(double)m;
xi[i] = ii[i]/(double)m;
}
free(rr);
free(ii);
}
__declspec(dllexport) void dft2(int m,int n,int flag,double *rr, double *ii)
{
void idft(int m, double *xr, double *xi);
void dft(int m, double *xr, double *xi);
double *xr,*xi;
int x,y;
xr = malloc(m * sizeof(double));
xi = malloc(m * sizeof(double));
if (rr == NULL || ii == NULL) return;
for(y = 0; y<n; y++) {
#pragma omp parallel for
for(x = 0; x<m; x++) {
xr[x] = rr[y*m+x];
xi[x] = ii[y*m+x];
}
if(flag>0) dft(m, xr, xi);
else idft(m, xr, xi);
#pragma omp parallel for
for(x = 0; x<m; x++) {
rr[y*m+x] = xr[x];
ii[y*m+x] = xi[x];
}
}
free(xr);
free(xi);
xr = malloc(n * sizeof(double));
xi = malloc(n * sizeof(double));
for(x = 0; x<m; x++) {
#pragma omp parallel for
for(y = 0; y<n; y++) {
xr[y] = rr[y*m+x];
xi[y] = ii[y*m+x];
}
if(flag>0) dft (n, xr, xi);
else idft (n, xr, xi);
#pragma omp parallel for
for(y = 0; y<n; y++) {
rr[y*m+x] = xr[y];
ii[y*m+x] = xi[y];
}
}
free(xr);
free(xi);
}
音声信号処理 - しばっち
2024/10/13 (Sun) 07:55:09
音声信号処理
READWAVとWRITEWAVルーチンを組み合わせると音声信号処理(音声加工処理)ができます。
※処理(加工)内容によっては原音にはない高周波成分が生じて耳障りなノイズ
となる場合があります。スピーカーにも悪いのでくれぐれも再生時の音量に気を付けてください。
https://decimalbasic.ninja-web.net/log/article/b/basic/105/kdhrmc/kdhrmc.html
入力wavファイルのサンプルビットが32ビットや24ビットで出力ファイルを16ビットのようにビット数を
下げると音質は劣化します。(階調数が減少し劣化します)
入力wavファイルのサンプルビットが8ビットや16ビットで出力ファイルを32ビットのようにビット数を
上げても音質は変わりません。(線形変換なので階調数は変わらない)
出力値の範囲が-1~1を超えるとクリッピングノイズが発生します。
その場合は適当なパラメータを掛けるか、正規化処理してください。
但し、故意にクリッピングノイズを発生させ音を歪ませる(ファズ、オーバードライブ、ディストーション)
加工処理もあります。
2進モードで実行してください
LET SIZE=44100*200 ! バッファーサイズ 44100Hzで200秒分
DIM LIN(SIZE),RIN(SIZE),LOUT(SIZE),ROUT(SIZE)
FILE GETOPENNAME F$,"読み込み WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL READWAV(F$,NUM,CHANNEL,SAMPLEFREQ,SAMPLEBIT,LIN,RIN,ERR)
IF ERR>0 THEN STOP
!----------------------------------------ここまでが読み込み部 これよりデータ処理部(加工部)
FOR I=1 TO NUM
LET LOUT(I)=LIN(NUM-I+1) ! 逆再生
LET ROUT(I)=RIN(NUM-I+1)
NEXT I
!----------------------------------------ここより以下書き出し部
FILE GETSAVENAME F$,"保存 WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL WRITEWAV(F$,NUM,CHANNEL,SAMPLEFREQ,SAMPLEBIT,LOUT,ROUT)
END
---------------------------------------------------------------
読み込み部はREADAIFFやREADSNDやREADCSV等と書き換えできます。
書き出し部はWRITEAIFFやWRITESNDやWRITECSV等と書き換えできます。
以下使用例(データ処理部のみ抜粋)
https://www.utsbox.com/?page_id=1316#エフェクターの実装例
https://ime.ist.hokudai.ac.jp/~aoki/laboratory04.html
https://www.utsbox.com/?p=1505
https://nettyukobo.com/timestretch_speedup/
https://teckonestep.com/
FOR I=1 TO NUM
LET LOUT(I)=-LIN(I) ! 位相反転
LET ROUT(I)=-RIN(I)
NEXT I
---------------------------------------------------------------
FOR I=1 TO NUM
LET LOUT(I)=LIN(I)-RIN(I) ! カラオケ化(ボーカルキャンセラー CD音源限定?)
LET ROUT(I)=RIN(I)-LIN(I)
NEXT I
---------------------------------------------------------------
FOR I=1 TO NUM
LET LOUT(I)=SGN(LIN(I))*MOD(ABS(LIN(I)),.3) ! 剰余
LET ROUT(I)=SGN(RIN(I))*MOD(ABS(RIN(I)),.3)
NEXT I
---------------------------------------------------------------
!INPUT PROMPT "閾値(1-100)%=":LEV
!INPUT PROMPT "増幅率 (0-10db)=":DB
LET LEV=70
LET DB=5
LET LEV=LEV/100
LET GAIN=10^(DB/20)
FOR K=1 TO NUM
LET LOUT(K)=LIN(K)*GAIN ! 5db増幅(ファズ、オーバードライブ、ディストーション)
IF ABS(LOUT(K))>=LEV THEN LET LOUT(K)=SGN(LOUT(K))*LEV
LET ROUT(K)=RIN(K)*GAIN
IF ABS(ROUT(K))>=LEV THEN LET ROUT(K)=SGN(ROUT(K))*LEV
NEXT K
---------------------------------------------------------------
LET GAIN=20 ! 増幅率(%)
FOR K=1 TO NUM
LET LOUT(K)=LIN(K)*(100+GAIN)/100 ! ファズ、オーバードライブ、ディストーション
LET ROUT(K)=RIN(K)*(100+GAIN)/100
NEXT K
---------------------------------------------------------------
LET LEV=.6
MAT LOUT=LIN
MAT ROUT=RIN
FOR K=1 TO NUM
IF ABS(LOUT(K))>=LEV THEN LET LOUT(K)=SGN(LOUT(K))*LEV ! リミッター
IF ABS(ROUT(K))>=LEV THEN LET ROUT(K)=SGN(ROUT(K))*LEV
NEXT K
---------------------------------------------------------------
IF CHANNEL<>2 THEN
PRINT "ステレオではありません"
STOP
END IF
INPUT PROMPT "左右バランス 0-100%":BAL
LET BAL=BAL/100
FOR K=1 TO NUM
LET LOUT(K)=LIN(K)*BAL+RIN(K)*(1-BAL) ! ステレオ→モノラル化
NEXT K
LET CHANNEL=1
---------------------------------------------------------------
IF CHANNEL<>2 THEN
PRINT "ステレオではありません"
STOP
END IF
FOR I=1 TO NUM
LET LOUT(I)=LIN(I)*RIN(I)
NEXT I
LET CHANNEL=1
---------------------------------------------------------------
IF CHANNEL<>1 THEN
PRINT "モノラルではありません"
STOP
END IF
LET D=.005*SAMPLINGFREQ
FOR K=1 TO NUM
LET M=INT(K-D)
IF M<=0 THEN LET M=1
LET LOUT(K)=LIN(K)+LIN(M) ! 疑似ステレオ化
LET ROUT(K)=LIN(K)-LIN(M)
NEXT K
LET CHANNEL=2
---------------------------------------------------------------
IF CHANNEL<>2 THEN
PRINT "ステレオではありません"
STOP
END IF
INPUT PROMPT "左右バランス(0-100%) =":BALANCE
LET BALANCE=BALANCE/100
FOR K=1 TO NUM
LET LOUT(K)=LIN(K)*BALANCE+(1-BALANCE)*RIN(K) ! ステレオミックス
LET ROUT(K)=RIN(K)*BALANCE+(1-BALANCE)*LIN(K)
NEXT K
---------------------------------------------------------------
LET FREQ=8000
LET BW=1
LET GAIN=3
CALL BIQUAD(LIN,0,NUM,SAMPLINGFREQ,FREQ,1/SQR(2),BW,GAIN,LOUT) ! ローパスフィルタ 遮断域周波数8000Hz~
CALL BIQUAD(RIN,0,NUM,SAMPLINGFREQ,FREQ,1/SQR(2),BW,GAIN,ROUT)
---------------------------------------------------------------
LET VOL=.8
FOR K=1 TO NUM
LET LMIN=MIN(LMIN,LIN(K))
LET LMAX=MAX(LMAX,LIN(K))
LET RMIN=MIN(RMIN,RIN(K))
LET RMAX=MAX(RMAX,RIN(K))
NEXT K
FOR K=1 TO NUM
LET LOUT(K)=(LIN(K)-LMIN)/(LMAX-LMIN)*VOL ! 音量レベル正規化(音量を一定量にします)
IF CHANNEL=2 THEN LET ROUT(K)=(RIN(K)-RMIN)/(RMAX-RMIN)*VOL
NEXT K
---------------------------------------------------------------
FOR K=1 TO NUM
LET LMAX=MAX(LMAX,ABS(LIN(K)))
LET RMAX=MAX(RMAX,ABS(RIN(K)))
NEXT K
MAT LOUT=(1/LMAX)*LIN ! 音量レベル正規化
IF CHANNEL=2 THEN MAT ROUT=(1/RMAX)*RIN
---------------------------------------------------------------
https://4ch.site/synth_lfo1/
https://kensukeinage.com/synth_lfo/
LET FREQ=5
FOR K=1 TO NUM
LET VOL=SIN(K*FREQ/SAMPLINGFREQ*2*PI)*.5+.5 ! トレモロ LFO(低周波発振器) LFOは必ずしもSIN波である必要はない(方形波、三角波、のこぎり波 etc)
LET LOUT(K)=VOL*LIN(K)
LET ROUT(K)=VOL*RIN(K)
NEXT K
---------------------------------------------------------------
LET FREQ=.25
FOR K=1 TO NUM
LET LOUT(K)=LIN(K)*ABS(SIN(FREQ/SAMPLINGFREQ*2*PI*K)) ! パンナー、回転スピーカー LFO(低周波発振器)
LET ROUT(K)=RIN(K)*ABS(COS(FREQ/SAMPLINGFREQ*2*PI*K))
NEXT K
---------------------------------------------------------------
INPUT PROMPT "周期 ":FREQ ! 0~10Hz
FOR K=1 TO NUM
LET A=SIN(K*2*PI*FREQ/SAMPLINGFREQ)*.5+.5 ! LFO(低周波発振器)
LET LOUT(K)=LIN(K)*A
LET ROUT(K)=RIN(K)*(1-A)
NEXT K
---------------------------------------------------------------
LET DEPTH=1
LET FREQ=.2
FOR K=1 TO NUM
LET A=1+DEPTH*SIN(2*PI*FREQ*K/SAMPLINGFREQ) ! オートパン LFO(低周波発振器)
LET LOUT(K)=LIN(K)*A/2
LET A=1+DEPTH*SIN(2*PI*FREQ*K/SAMPLINGFREQ+PI)
LET ROUT(K)=RIN(K)*A/2
NEXT K
---------------------------------------------------------------
LET N=6 ! 階調数
FOR K=1 TO NUM
LET LOUT(K)=IP(LIN(K)*N)/N ! ポスタリゼーション
LET ROUT(K)=IP(RIN(K)*N)/N
NEXT K
---------------------------------------------------------------
FOR K=1 TO NUM
LET LOUT(K)=SGN_(LIN(K))*(1-ABS(LIN(K))) ! NOT演算
LET ROUT(K)=SGN_(RIN(K))*(1-ABS(RIN(K)))
NEXT K
EXTERNAL FUNCTION SGN_(X)
IF X>=0 THEN
LET SGN_=1
ELSE
LET SGN_=-1
END IF
END FUNCTION
---------------------------------------------------------------
RANDOMIZE
LET LEV=.2
FOR K=1 TO NUM
IF RND<RATE THEN
LET LOUT(K)=LIN(K)+RND*LEV-LEV/2 ! ノイズ付加
LET ROUT(K)=RIN(K)+RND*LEV-LEV/2
ELSE
LET LOUT(K)=LIN(K)
LET ROUT(K)=RIN(K)
END IF
NEXT K
---------------------------------------------------------------
LET THRESHOLD=.02 ! 要レベル調整
FOR K=1 TO NUM
LET LOUT(K)=LIN(K)
LET ROUT(K)=RIN(K)
IF ABS(LOUT(K))<=THRESHOLD THEN LET LOUT(K)=0 ! ノイズ除去(ノイズゲート)
IF ABS(ROUT(K))<=THRESHOLD THEN LET ROUT(K)=0
NEXT K
---------------------------------------------------------------
LET TAP=4
DIM A(2*TAP+1),B(2*TAP+1)
!LET T=SAMPLINGFREQ/1000
LET T=1
FOR I=1 TO NUM
FOR J=-TAP TO TAP
IF I+T*J>=1 AND I+T*J<=NUM THEN
LET A(J+1+TAP)=LIN(I+T*J)
LET B(J+1+TAP)=RIN(I+T*J)
ELSE
LET A(J+1+TAP)=0
LET B(J+1+TAP)=0
END IF
NEXT J
LET LOUT(I)=SORT(2*TAP+1,A,TAP) ! メディアン(中央値)フィルタ
LET ROUT(I)=SORT(2*TAP+1,B,TAP)
NEXT I
EXTERNAL FUNCTION SORT(N,A(),M)
FOR I=1 TO N-1
FOR J=I+1 TO N
IF A(I)>A(J) THEN
SWAP A(I),A(J)
END IF
NEXT J
NEXT I
LET SORT=A(M)
END FUNCTION
---------------------------------------------------------------
!INPUT PROMPT "ディレイタイム(ms)=":DELAYTIME
LET DELAYTIME=100 ! 100ms
LET DELAYTIME=DELAYTIME/1000
LET T=INT(SAMPLINGFREQ*DELAYTIME)
LET ITER=3
FOR I=1 TO NUM
LET S1=0
LET S2=0
FOR K=0 TO ITER-1 ! エコー,ディレイ
IF I-T*K>0 THEN
LET S1=S1+LIN(I-T*K)
LET S2=S2+RIN(I-T*K)
END IF
NEXT K
LET LOUT(I)=S1/ITER
LET ROUT(I)=S2/ITER
NEXT I
---------------------------------------------------------------
INPUT PROMPT "ディレイタイム(ms)=":SECOND
LET SECOND=SECOND/1000
INPUT PROMPT "減衰率(0 - 100%)=":RATE
LET RATE=RATE/100
INPUT PROMPT "ループ回数=":CNT
LET DELAY=INT(SAMPLINGFREQ*SECOND)
FOR I=0 TO CNT-1
LET T=T+RATE^I
NEXT I
FOR I=1 TO NUM
FOR J=1 TO CHANNEL
SELECT CASE J
CASE 1
FOR K=0 TO CNT-1
IF I-DELAY*K>0 THEN LET LOUT(I)=LOUT(I)+LIN(I-DELAY*K)*RATE^K
NEXT K
CASE 2
FOR K=0 TO CNT-1
IF I-DELAY*K>0 THEN LET ROUT(I)=ROUT(I)+RIN(I-DELAY*K)*RATE^K
NEXT K
END SELECT
NEXT J
LET LOUT(I)=LOUT(I)/T
LET ROUT(I)=ROUT(I)/T
NEXT I
---------------------------------------------------------------
https://nettyukobo.com/vibrato/
LET D=0.002*SAMPLINGFREQ
LET DEPTH=0.002*SAMPLINGFREQ
LET FREQ=5
FOR K=1 TO NUM
LET TAU=D+DEPTH*SIN(2*PI*FREQ*K/SAMPLINGFREQ) ! LFO(低周波発振器)
LET T=K-TAU
LET M=IP(T)
LET DELTA=FP(T)
IF M>=1 AND M+1<=NUM THEN
LET LOUT(K)=DELTA*LIN(M+1)+(1-DELTA)*LIN(M) ! ヴィブラート
LET ROUT(K)=DELTA*RIN(M+1)+(1-DELTA)*RIN(M)
ELSE
LET LOUT(K)=(1-DELTA)*LIN(K)
LET ROUT(K)=(1-DELTA)*RIN(K)
END IF
NEXT K
---------------------------------------------------------------
https://nettyukobo.com/comb_filter_reverb/
https://nettyukobo.com/all_pass_reverberator/
LET G=.9 ! 減衰率
LET D=SAMPLINGFREQ*.04 ! 遅延時間
FOR K=1 TO NUM
IF K-D>0 THEN
LET LOUT(K)=LIN(K)+G*LOUT(K-D) ! リヴァーブ、エコー
LET ROUT(K)=RIN(K)+G*ROUT(K-D)
! LET LOUT(K)=-G*LIN(K)+LIN(K-D)+G*LOUT(K-D)
! LET ROUT(K)=-G*RIN(K)+RIN(K-D)+G*ROUT(K-D)
ELSE
LET LOUT(K)=LIN(K)
LET ROUT(K)=RIN(K)
END IF
NEXT K
FOR K=1 TO NUM
LET LMAX=MAX(LMAX,ABS(LOUT(K)))
LET RMAX=MAX(RMAX,ABS(ROUT(K)))
NEXT K
MAT LOUT=(1/LMAX)*LOUT ! 正規化
IF CHANNEL=2 THEN MAT ROUT=(1/RMAX)*ROUT
---------------------------------------------------------------
LET FREQ=150
FOR K=1 TO NUM
LET A=SIN(K*2*PI*FREQ/SAMPLINGFREQ) ! ボイスチェンジャー LFO(低周波発振器)
LET LOUT(K)=LIN(K)*A
LET ROUT(K)=RIN(K)*A
NEXT K
---------------------------------------------------------------
https://nettyukobo.com/chorus_flanger/
LET D=SAMPLINGFREQ*.002
LET FREQ=.5
LET DEPTH=SAMPLINGFREQ*.002
FOR K=1 TO NUM
LET TAU=D+DEPTH*SIN(2*PI*FREQ*K/SAMPLINGFREQ) ! LFO(低周波発振器)
LET T=K-TAU
LET M=IP(T)
LET DELTA=FP(T)
IF M>0 AND M+1<=NUM THEN ! コーラス、フランジャー
LET LOUT(K)=LIN(K)+DELTA*LIN(M+1)+(1-DELTA)*LIN(M)
LET ROUT(K)=RIN(K)+DELTA*RIN(M+1)+(1-DELTA)*RIN(M)
ELSE
LET LOUT(K)=LIN(K)
LET ROUT(K)=RIN(K)
END IF
NEXT K
FOR K=1 TO NUM
LET LMAX=MAX(LMAX,ABS(LOUT(K)))
LET RMAX=MAX(RMAX,ABS(ROUT(K)))
NEXT K
MAT LOUT=(1/LMAX)*LOUT ! 正規化
IF CHANNEL=2 THEN MAT ROUT=(1/RMAX)*ROUT
---------------------------------------------------------------
PRINT "演奏時間";NUM/SAMPLINGFREQ;"秒"
INPUT PROMPT "切出し開始位置(秒) ":FS
INPUT PROMPT "切出し終了位置(秒) ":FE
LET FS=FS*SAMPLINGFREQ
LET FE=FE*SAMPLINGFREQ
FOR K=FS TO FE ! 切出し
LET N=N+1
LET LOUT(N)=LIN(K)
LET ROUT(N)=RIN(K)
NEXT K
---------------------------------------------------------------
PRINT "再生時間";NUM/SAMPLINGFREQ;"秒"
INPUT PROMPT "切取り開始位置(秒) ":FS
INPUT PROMPT "切取り終了位置(秒) ":FE
LET FS=FS*SAMPLINGFREQ
LET FE=FE*SAMPLINGFREQ
IF FS>FE THEN SWAP FS,FE
IF FE>NUM THEN LET FE=NUM
FOR K=1 TO FS ! 切取り
LET N=N+1
LET LOUT(N)=LIN(K)
LET ROUT(N)=RIN(K)
NEXT K
FOR K=FE TO NUM
LET N=N+1
LET LOUT(N)=LIN(K)
LET ROUT(N)=RIN(K)
NEXT K
---------------------------------------------------------------
FOR K=1 TO NUM
IF ABS(LIN(K))>1E-3 OR ABS(RIN(K))>1E-3 THEN ! 先頭無音部分(要レベル調整)
LET KS=K
EXIT FOR
END IF
NEXT K
FOR K=NUM TO 1 STEP -1
IF ABS(LIN(K))>1E-3 OR ABS(RIN(K))>1E-3 THEN ! 後方無音部分(要レベル調整)
LET KE=K
EXIT FOR
END IF
NEXT K
FOR K=KS TO KE ! 無音カット
LET N=N+1
LET LOUT(N)=LIN(K)
LET ROUT(N)=RIN(K)
NEXT K
---------------------------------------------------------------
MAT LOUT=LIN
MAT ROUT=RIN
LET PLAYTIME=3 ! 前後3秒
LET N=INT(SAMPLINGFREQ*PLAYTIME)
FOR K=1 TO N ! フェードイン
LET LOUT(K)=LIN(K)*K/N
LET ROUT(K)=RIN(K)*K/N
NEXT K
FOR K=NUM-N TO NUM ! フェードアウト
LET LOUT(K)=LIN(K)*(NUM-K)/N
LET ROUT(K)=RIN(K)*(NUM-K)/N
NEXT K
---------------------------------------------------------------
LET T=SAMPLINGFREQ*.001
FOR I=1 TO NUM STEP T
LET L=-2
LET R=-2
FOR J=0 TO T-1
IF L<ABS(LIN(I+J)) THEN ! 最大値
LET L=ABS(LIN(I+J))
LET LSIGN=SGN(LIN(I+J))
END IF
IF R<ABS(RIN(I+J)) THEN
LET R=ABS(RIN(I+J))
LET RSIGN=SGN(RIN(I+J))
END IF
NEXT J
FOR J=0 TO T-1
LET LOUT(I+J)=L*LSIGN
LET ROUT(I+J)=R*RSIGN
NEXT J
NEXT I
---------------------------------------------------------------
LET TAP=5
FOR I=1 TO NUM
LET L=10000
LET R=10000
FOR J=0 TO TAP-1
IF I+J<=NUM THEN
LET L=MIN(L,LIN(I+J)) ! 最小値
LET R=MIN(R,RIN(I+J))
END IF
NEXT J
LET LOUT(I)=L
LET ROUT(I)=R
NEXT I
---------------------------------------------------------------
LET TAP=5
FOR I=1 TO NUM
LET L=-10000
LET R=-10000
LET LSIGN=1
LET RSIGN=1
FOR J=0 TO TAP-1
IF I+J<=NUM THEN
LET L=MAX(L,ABS(LIN(I+J))) ! 最大値
LET R=MAX(R,ABS(RIN(I+J)))
LET LSIGN=LSIGN*SGN_(LIN(I+J))
LET RSIGN=RSIGN*SGN_(RIN(I+J))
END IF
NEXT J
LET LOUT(I)=L*LSIGN
LET ROUT(I)=R*RSIGN
NEXT I
---------------------------------------------------------------
LET TAP=5
FOR I=1 TO NUM
LET L=1
LET R=1
FOR J=0 TO TAP-1
IF I+J<=NUM THEN
LET L=L*LIN(I+J) ! 掛け算
LET R=R*RIN(I+J)
END IF
NEXT J
LET LOUT(I)=L
LET ROUT(I)=R
NEXT I
---------------------------------------------------------------
https://ja.wikipedia.org/wiki/ミンコフスキー距離
LET TAP=5
LET N=3.5
FOR I=1 TO NUM
LET L=0
LET R=0
LET LSIGN=1
LET RSIGN=1
FOR J=0 TO TAP-1
IF I+J<=NUM THEN
LET L=L+ABS(LIN(I+J))^N ! ミンコフスキー距離
LET R=R+ABS(RIN(I+J))^N
LET LSIGN=LSIGN*SGN_(LIN(I+J))
LET RSIGN=RSIGN*SGN_(RIN(I+J))
END IF
NEXT J
LET LOUT(I)=L^(1/N)*LSIGN
LET ROUT(I)=R^(1/N)*RSIGN
NEXT I
---------------------------------------------------------------
LET TAP=5
LET N=3.5
FOR I=1 TO NUM
LET L=0
LET R=0
LET LSIGN=1
LET RSIGN=1
FOR J=0 TO TAP-1
IF I+J<=NUM THEN
LET L=L+ABS(LIN(I+J))^(1/N) ! ミンコフスキー距離
LET R=R+ABS(RIN(I+J))^(1/N)
LET LSIGN=LSIGN*SGN_(LIN(I+J))
LET RSIGN=RSIGN*SGN_(RIN(I+J))
END IF
NEXT J
LET LOUT(I)=L^N*LSIGN
LET ROUT(I)=R^N*RSIGN
NEXT I
---------------------------------------------------------------
https://ja.wikipedia.org/wiki/幾何平均
LET TAP=5
FOR I=1 TO NUM
LET L=1
LET R=1
LET LSIGN=1
LET RSIGN=1
FOR J=0 TO TAP-1
IF I+J<=NUM THEN
LET L=L*ABS(LIN(I+J)) ! 相乗平均
LET R=R*ABS(RIN(I+J))
LET LSIGN=LSIGN*SGN_(LIN(I+J))
LET RSIGN=RSIGN*SGN_(RIN(I+J))
END IF
NEXT J
LET LOUT(I)=L^(1/TAP)*LSIGN
LET ROUT(I)=R^(1/TAP)*RSIGN
NEXT I
---------------------------------------------------------------
https://ja.wikipedia.org/wiki/調和平均
LET TAP=5
FOR I=1 TO NUM
LET L=0
LET R=0
LET LSIGN=1
LET RSIGN=1
LET FL=0
LET FR=0
FOR J=0 TO TAP-1
IF I+J<=NUM THEN
IF LIN(I+J)=0 THEN
LET FL=1
ELSE
LET L=L+1/ABS(LIN(I+J)) ! 調和平均
END IF
IF RIN(I+J)=0 THEN
LET FR=1
ELSE
LET R=R+1/ABS(RIN(I+J))
END IF
LET LSIGN=LSIGN*SGN_(LIN(I+J))
LET RSIGN=RSIGN*SGN_(RIN(I+J))
END IF
NEXT J
IF FL=0 THEN LET LOUT(I)=TAP/L*LSIGN ELSE LET LOUT(I)=0
IF FR=0 THEN LET ROUT(I)=TAP/R*RSIGN ELSE LET ROUT(I)=0
NEXT I
---------------------------------------------------------------
https://ja.wikipedia.org/wiki/論理演算
LET TAP=5
FOR I=1 TO NUM
LET L=0
LET R=0
LET LSIGN=1
LET RSIGN=1
FOR J=0 TO TAP-1
IF I+J<=NUM THEN
LET L=PXOR(L,ABS(LIN(I+J))) ! XOR演算
LET R=PXOR(R,ABS(RIN(I+J)))
LET LSIGN=LSIGN*SGN_(LIN(I+J))
LET RSIGN=RSIGN*SGN_(RIN(I+J))
END IF
NEXT J
LET LOUT(I)=L*LSIGN
LET ROUT(I)=R*RSIGN
NEXT I
EXTERNAL FUNCTION POR(X,Y) ! 0-0:0,0-1:1,1-0:1,1-1:1
LET POR=MIN(X+Y,1)
!LET POR=1-(1-X)*(1-Y)
END FUNCTION
EXTERNAL FUNCTION PAND(X,Y) ! 0-0:0,0-1:0,1-0:0,1-1:1
LET PAND=X*Y
END FUNCTION
EXTERNAL FUNCTION PXOR(X,Y) ! 0-0:0,0-1:1,1-0:1,1-1:0
LET PXOR=(1-X)*Y+(1-Y)*X
END FUNCTION
EXTERNAL FUNCTION PNOT(X)
LET PNOT=1-X
END FUNCTION
EXTERNAL FUNCTION PEQV(X,Y)
LET PEQV=PNOT(PXOR(X,Y))
END FUNCTION
EXTERNAL FUNCTION PIMP(X,Y) ! 0-0:1,0-1:1,1-0:0,1-1:1
LET PIMP=(1-X)*(1-Y)+(1-X)*Y+X*Y
END FUNCTION
EXTERNAL FUNCTION PNOR(X,Y)
LET PNOR=PNOT(POR(X,Y))
END FUNCTION
EXTERNAL FUNCTION PNAND(X,Y)
LET PNAND=PNOT(PAND(X,Y))
END FUNCTION
EXTERNAL FUNCTION PNIMP(X,Y)
LET PNIMP=PNOT(PIMP(X,Y))
END FUNCTION
EXTERNAL FUNCTION PIMP2(X,Y) ! 0-0:0,0-1:1,1-0:0,1-1:0
LET PIMP2=(1-X)*Y
END FUNCTION
EXTERNAL FUNCTION PNIMP2(X,Y)
LET PNIMP2=PNOT(PIMP2(X,Y))
END FUNCTION
---------------------------------------------------------------
http://comp.cs.ehime-u.ac.jp/~okano/na/小テスト6補足資料.pdf
FOR K=2 TO NUM
LET LOUT(K)=LIN(K)-LIN(K-1) ! 1次微分
LET ROUT(K)=RIN(K)-RIN(K-1)
!LET LOUT(K)=LIN(K)-2*LIN(K-1)+LIN(K-2) ! 2次微分
!LET ROUT(K)=RIN(K)-2*RIN(K-1)+RIN(K-2)
!LET LOUT(K)=LIN(K)-3*LIN(K-1)+3*LIN(K-2)-LIN(K-3) ! 3次微分
!LET ROUT(K)=RIN(K)-3*RIN(K-1)+3*RIN(K-2)-RIN(K-3)
!LET LOUT(K)=LIN(K)-4*LIN(K-1)+6*LIN(K-2)-4*LIN(K-3)+LIN(K-4) ! 4次微分
!LET ROUT(K)=RIN(K)-4*RIN(K-1)+6*RIN(K-2)-4*RIN(K-3)+RIN(K-4)
!LET LOUT(K)=LIN(K)-5*LIN(K-1)+10*LIN(K-2)-10*LIN(K-3)+5*LIN(K-4)-LIN(K-5) ! 5次微分
!LET ROUT(K)=RIN(K)-5*RIN(K-1)+10*RIN(K-2)-10*RIN(K-3)+5*RIN(K-4)-RIN(K-5)
NEXT K
EXTERNAL FUNCTION DF(A(),N) ! 1次微分
LET DF=A(N)-A(N-1)
END FUNCTION
EXTERNAL FUNCTION DF2(A(),N) ! 2次微分
LET DF2=DF(A,N)-DF(A,N-1)
END FUNCTION
EXTERNAL FUNCTION DF3(A(),N) ! 3次微分
LET DF3=DF2(A,N)-DF2(A,N-1)
END FUNCTION
!EXTERNAL FUNCTION DF(LEV,A(),N)
!IF LEV=1 THEN
! LET DF=A(N)-A(N-1)
!ELSE
! LET DF=DF(LEV-1,A,N)-DF(LEV-1,A,N-1)
!END IF
!END FUNCTION
---------------------------------------------------------------
画像処理でいうアンシャープ化
LET TAP=5
FOR I=2 TO NUM
LET L(I)=LIN(I)-LIN(I-1) ! 1次微分
LET R(I)=RIN(I)-RIN(I-1)
NEXT I
FOR I=1 TO NUM
LET S1=0
LET S2=0
FOR J=0 TO TAP-1
IF I+J<=NUM THEN
LET S1=S1+LIN(I+J)/TAP
LET S2=S2+RIN(I+J)/TAP
END IF
NEXT J
LET LL(I)=S1
LET RR(I)=S2
NEXT I
FOR I=1 TO NUM
LET LOUT(I)=LL(I)-LIN(I)+L(I) ! ボカシ-元信号+差分=アンシャープ
LET ROUT(I)=RR(I)-RIN(I)+R(I)
NEXT I
FOR K=1 TO NUM
LET LMAX=MAX(LMAX,ABS(LOUT(K)))
LET RMAX=MAX(RMAX,ABS(ROUT(K)))
NEXT K
MAT LOUT=(1/LMAX)*LOUT
IF CHANNEL=2 THEN MAT ROUT=(1/RMAX)*ROUT
---------------------------------------------------------------
画像処理でいう強調化
FOR K=3 TO NUM
LET L(K)=LIN(K)-2*LIN(K-1)+LIN(K-2) ! 2次微分
LET R(K)=RIN(K)-2*RIN(K-1)+RIN(K-2)
NEXT K
FOR K=1 TO NUM
LET LOUT(K)=LIN(K)+L(K) ! 強調
LET ROUT(K)=RIN(K)+R(K)
NEXT K
FOR K=1 TO NUM
LET LMAX=MAX(LMAX,ABS(LOUT(K)))
LET RMAX=MAX(RMAX,ABS(ROUT(K)))
NEXT K
MAT LOUT=(1/LMAX)*LOUT
IF CHANNEL=2 THEN MAT ROUT=(1/RMAX)*ROUT
---------------------------------------------------------------
IF POS("80 160 110 220 480",STR$(INT(SAMPLINGFREQ/100)))>0 THEN ! サンプリング周波数を倍にする(倍速再生、音程も倍になる)
LET SAMPLINGFREQ=SAMPLINGFREQ*2
ELSE
STOP
END IF
---------------------------------------------------------------
FOR K=1 TO NUM STEP 2 ! 倍速再生 ※但し、音程も変わります。
LET N=N+1
LET LOUT(N)=LIN(K)
LET ROUT(N)=RIN(K)
NEXT K
---------------------------------------------------------------
INPUT PROMPT "再生速度 (1-500%) ":SPEED
LET SPEED=SPEED/100
DIM LOUT(SIZE/SPEED+1),ROUT(SIZE/SPEED+1) ! ファイルサイズが増減します
FOR K=1 TO NUM STEP SPEED ! 再生速度変更 ※但し、音程も変わります。
LET N=N+1
LET T=FP(K)
LET U=IP(K)
IF K<NUM THEN
LET LOUT(N)=LIN(U)*(1-T)+LIN(U+1)*T ! 線形補間
LET ROUT(N)=RIN(U)*(1-T)+LIN(U+1)*T
ELSE
LET LOUT(N)=LIN(U)*(1-T)
LET ROUT(N)=RIN(U)*(1-T)
END IF
NEXT K
---------------------------------------------------------------
https://ja.wikipedia.org/wiki/Sinc関数
LET TAP=2 ! 次数
INPUT PROMPT "SPEED (1-500%) ":SPEED
LET SPEED=SPEED/100
DIM LOUT(SIZE/SPEED+1),ROUT(SIZE/SPEED+1)
FOR K=1 TO NUM STEP SPEED ! 再生速度変更 ※但し、音程も変わります。
LET N=N+1
LET T=FP(K)
LET U=IP(K)
LET S1=0
LET S2=0
FOR J=-TAP TO TAP
IF K+J>0 AND K+J<=NUM THEN
LET S1=S1+LIN(U+J)*SINC(T+J) ! sinc補間
LET S2=S2+RIN(U+J)*SINC(T+J)
END IF
NEXT J
LET LOUT(N)=S1
LET ROUT(N)=S2
NEXT K
EXTERNAL FUNCTION SINC(X)
IF X=0 THEN
LET SINC=1
ELSE
LET SINC=SIN(X*PI)/(X*PI)
END IF
END FUNCTION
---------------------------------------------------------------
IF POS("80 160 110 220 480",STR$(INT(SAMPLINGFREQ/100)))>0 THEN ! サンプリング周波数を倍にしてサンプル数も倍にして音質改善?
LET SAMPLINGFREQ=SAMPLINGFREQ*2
ELSE
STOP
END IF
FOR K=1 TO NUM STEP .5
LET N=N+1
LET I=IP(K)
LET F=FP(K)
IF I+1<=NUM THEN
LET LOUT(N)=LIN(I)*(1-F)+LIN(I+1)*F
LET ROUT(N)=RIN(I)*(1-F)+RIN(I+1)*F
ELSE
LET LOUT(N)=LIN(I)*(1-F)
LET ROUT(N)=RIN(I)*(1-F)
END IF
NEXT K
---------------------------------------------------------------
DIM FREQ(9)
MAT READ FREQ
DATA 8000,11025,16000,22050,32000,44100,48000,96000,192000
PRINT "サンプリング周波数";SAMPLINGFREQ
INPUT PROMPT "サンプリング周波数変換 8000Hz(1) 11025Hz(2) 16000Hz(3) 22050Hz(4) 32000Hz(5) 44100Hz(6) 48000Hz(7) 96000Hz(8) 192000Hz(9)":MODE
LET ST=SAMPLINGFREQ/FREQ(MODE)
DIM LOUT(SIZE),ROUT(SIZE)
FOR K=1 TO NUM STEP ST
LET T=FP(K)
LET U=IP(K)
LET N=N+1
LET S1=0
LET S2=0
FOR J=-2 TO 2
IF U+J>0 AND U+J<=NUM THEN
LET S1=S1+LIN(U+J)*SINC(T+J)
LET S2=S2+RIN(U+J)*SINC(T+J)
END IF
NEXT J
LET LOUT(K)=S1
LET ROUT(K)=S2
NEXT K
---------------------------------------------------------------
リングバッファーによるピッチシフト
https://ja.wikipedia.org/wiki/リングバッファ
LET BUFSIZE=SAMPLINGFREQ*.03
DIM LEFTRINGBUF(0 TO BUFSIZE-1),RIGHTRINGBUF(0 TO BUFSIZE-1)
LET PITCHSHIFT=2
FOR K=1 TO NUM
LET INDEX=MOD(K,BUFSIZE)
LET LEFTRINGBUF(INDEX)=LIN(K) ! リングバッファー
LET RIGHTRINGBUF(INDEX)=RIN(K)
LET N=K*PITCHSHIFT ! ピッチシフター、オクターバー
LET I=IP(N)
LET F=FP(N)
LET LOUT(K)=LEFTRINGBUF(MOD(I,BUFSIZE))*(1-F)+LEFTRINGBUF(MOD(I+1,BUFSIZE))*F
LET ROUT(K)=RIGHTRINGBUF(MOD(I,BUFSIZE))*(1-F)+RIGHTRINGBUF(MOD(I+1,BUFSIZE))*F
NEXT K
Re: 音声信号処理 - しばっち
2024/10/13 (Sun) 07:57:10
FOR I=1 TO NUM
LET LOUT(I)=F(LIN(I))*.5 ! 非線形変換
LET ROUT(I)=F(RIN(I))*.5
NEXT
EXTERNAL FUNCTION F(X)
LET F=SGN(SIN(ASIN(X))) ! 方形波
!LET F=ASIN(X)/PI*2 ! 三角波
!LET F=SIN(PI*ASIN(X))
!LET F=SIN(2*PI*X)
END FUNCTION
---------------------------------------------------------------
LET R=.4
FOR I=1 TO NUM
LET LOUT(I)=SGN(LIN(I))*ABS(LIN(I))^(1/R) ! 非線形変換
LET ROUT(I)=SGN(RIN(I))*ABS(RIN(I))^(1/R)
NEXT I
---------------------------------------------------------------
RANDOMIZE
LET M=RND*4
LET N=RND*4
SET WINDOW -1,1,-1,1
DRAW GRID(.2,.2)
FOR X=-1 TO 1 STEP 1/32
PLOT LINES:X,INTERPOLATION(X,-1,1,-1,1,M,N);
NEXT X
FOR I=1 TO NUM
LET LOUT(I)=INTERPOLATION(LIN(I),-1,1,-1,1,M,N) ! 非線形変換
LET ROUT(I)=INTERPOLATION(RIN(I),-1,1,-1,1,M,N)
NEXT I
EXTERNAL FUNCTION INTERPOLATION(X,XMIN,XMAX,YMIN,YMAX,M,N) ! XMIN<=X<=XMAX
LET X=MIN(XMAX,MAX(X,XMIN))
LET INTERPOLATION=(YMAX-YMIN)/(SGN(XMAX)*ABS(XMAX)^M-XMIN)^N*(SGN(X)*ABS(X)^M-XMIN)^N+YMIN
END FUNCTION
---------------------------------------------------------------
RANDOMIZE
LET M=RND*5
LET N=RND*5
LET P=RND*5
SET WINDOW -1,1,-1,1
DRAW GRID(.2,.2)
FOR X=-1 TO 1 STEP 1/32
PLOT LINES:X,INTERPOLATION(X,-1,1,-1,1,M,N,P);
NEXT X
FOR I=1 TO NUM
LET LOUT(I)=INTERPOLATION(LIN(I),-1,1,-1,1,M,N,P) ! 非線形変換
LET ROUT(I)=INTERPOLATION(RIN(I),-1,1,-1,1,M,N,P)
NEXT I
EXTERNAL FUNCTION INTERPOLATION(X,XMIN,XMAX,YMIN,YMAX,M,N,P) ! XMIN<=X<=XMAX
LET X=MIN(XMAX,MAX(X,XMIN))
LET T=(X-XMIN)/(XMAX-XMIN)
LET INTERPOLATION=YMIN*(1-T^M)^N+YMAX*T^P
END FUNCTION
---------------------------------------------------------------
LET N=10
DIM X(N),Y(N)
SET WINDOW -1,1,-1,1
DRAW GRID(.2,.2)
FOR I=1 TO N
READ X(I),Y(I)
PLOT LINES:X(I),Y(I);
NEXT I
DATA -1,1
DATA -.6,-1
DATA -.6,1
DATA -.2,-1
DATA -.2,1
DATA .2,-1
DATA .2,1
DATA .6,-1
DATA .6,1
DATA 1,-1
FOR I=1 TO NUM
LET LOUT(I)=F(LIN(I),N,X,Y) ! 線形変換
LET ROUT(I)=F(RIN(I),N,X,Y)
NEXT I
EXTERNAL FUNCTION F(XX,N,X(),Y()) !
FOR I=1 TO N-1
IF X(I)<=XX AND X(I+1)>=XX THEN
LET F=(Y(I+1)-Y(I))/(X(I+1)-X(I))*(XX-X(I))+Y(I)
EXIT FUNCTION
END IF
NEXT I
LET F=XX
END FUNCTION
---------------------------------------------------------------
DIM LUT(255)
SET WINDOW -1,1,-1,1
DRAW GRID(.2,.2)
FOR I=1 TO 255
READ LUT(I) ! ルックアップテーブル
PLOT LINES:2*I/255-1,LUT(I);
NEXT I
DATA -7.85426707962836E-3 ,-1.57141319943974E-2 ,-.023461508734477 ,-3.09781144044374E-2 ,-.038147213502212 ,-4.48553661866093E-2 ,-5.09941552129774E-2 ,-5.64618661668915E-2 ,-6.11650959381815E-2 ,-6.50202650522969E-2 ,-6.79550105078911E-2 ,-6.99094371484411E-2 ,-7.08372073065202E-2 ,-7.07064504819803E-2 ,-6.95004771250992E-2 ,-6.72182831637032E-2
DATA -6.38748347064068E-2 ,-5.95011253358703E-2 ,-5.41440015367571E-2 ,-4.78657550406853E-2 ,-4.07434841707331E-2 ,-3.28682295854111E-2 ,-.024343893110078 ,-1.52859515560646E-2 ,-5.81998051829323E-3 , 3.91999393392034E-3 , 1.37932950439433E-2 , 2.36545235399083E-2 , 3.33555889229312E-2 , 4.27478167486482E-2 , 5.16841032773653E-2 , 6.00210877438072E-2
DATA 6.76213117712769E-2 , 7.43553351423367E-2 , 8.01037772486475E-2 , 8.47592540804446E-2 , 8.82281815794658E-2 , 9.04324175603358E-2 , 9.13107161909428E-2 , .090819971192986 , 8.89362264549138E-2 , 8.56554356109361E-2 , 8.09939552968595E-2 , 7.49887602068642E-2 , .06769737170178 , .059197495512273 , 4.95863679901577E-2 , 3.89798143361773E-2
DATA 2.75110262199412E-2 , 1.53290701533799E-2 , 2.59714182913288E-3 ,-1.05094146635328E-2 ,-2.38053003322234E-2 ,-3.70976418213195E-2 ,-5.01885303826588E-2 ,-6.28776880496255E-2 ,-7.49652275556813E-2 ,-8.62544707216416E-2 ,-9.65547886636063E-2 ,-.105684426269286 ,-.113473272972373 ,-.119765541934187 ,-.124422320324079 ,-.127323954473516
DATA -.128372235255002 ,-.127492351091231 ,-.124634578510639 ,-.11977568310519 ,-.112920007081167 ,-.10410022328474 ,-9.33777395869012E-2 ,-8.08427417780899E-2 ,-6.66138675988017E-2 ,-5.08375091625488E-2 ,-3.36867457531462E-2 ,-1.53599137390094E-2 , 3.9211749184947E-3 , .023913349439273 , 4.43545116607216E-2 , 6.49663572269623E-2
DATA 8.54573576000593E-2 , .105525970261009 , .124864041138839 , .143160360394923 , .160104330237978 , .17538970148906 , .188718334184817 , .199803936624569 , .208375736948562 , .214182041590269 , .216993635776524 , .216606982650025 , .212847179546406 , .205570632452343 , .194667412674888 , .180063263231421
DATA .161721226384014 , .139642868045584 , .113869079426558 , 8.44804412139577E-2 , 5.15971407199358E-2 , 1.53784377407642E-2 ,-2.39783197353682E-2 ,-6.62391234096138E-2 ,-.111135164198182 ,-.158365106184254 ,-.207597752679449 ,-.258475077219701 ,-.310615587763502 ,-.363617988163652 ,-.417065097200656 ,-.470527982145922
DATA -.52357026100908 ,-.575752525353269 ,-.626636833865371 ,-.675791225768264 ,-.722794202674842 ,-.767239127617103 ,-.808738490738177 ,-.846927992503372 ,-.881470397252895 ,-.912059112461055 ,-.938421452154413 ,-.960321546537559 ,-.97756286393654 ,-.989990315647039 ,-.997491919112793 , 1
DATA .997491919112793 , .989990315647039 , .97756286393654 , .960321546537559 , .938421452154413 , .912059112461055 , .881470397252895 , .846927992503372 , .808738490738177 , .767239127617103 , .722794202674842 , .675791225768264 , .626636833865371 , .575752525353269 , .52357026100908 , .470527982145922
DATA .417065097200656 , .363617988163652 , .310615587763502 , .258475077219701 , .207597752679449 , .158365106184254 , .111135164198182 , 6.62391234096138E-2 , 2.39783197353682E-2 ,-1.53784377407642E-2 ,-5.15971407199358E-2 ,-8.44804412139577E-2 ,-.113869079426558 ,-.139642868045584 ,-.161721226384014 ,-.180063263231421
DATA -.194667412674888 ,-.205570632452343 ,-.212847179546406 ,-.216606982650025 ,-.216993635776524 ,-.214182041590269 ,-.208375736948562 ,-.199803936624569 ,-.188718334184817 ,-.17538970148906 ,-.160104330237978 ,-.143160360394923 ,-.124864041138839 ,-.105525970261009 ,-8.54573576000593E-2 ,-6.49663572269623E-2
DATA -4.43545116607216E-2 ,-.023913349439273 ,-3.9211749184947E-3 , 1.53599137390094E-2 , 3.36867457531462E-2 , 5.08375091625488E-2 , 6.66138675988017E-2 , 8.08427417780899E-2 , 9.33777395869012E-2 , .10410022328474 , .112920007081167 , .11977568310519 , .124634578510639 , .127492351091231 , .128372235255002 , .127323954473516
DATA .124422320324079 , .119765541934187 , .113473272972373 , .105684426269286 , 9.65547886636063E-2 , 8.62544707216416E-2 , 7.49652275556813E-2 , 6.28776880496255E-2 , 5.01885303826588E-2 , 3.70976418213195E-2 , 2.38053003322234E-2 , 1.05094146635328E-2 ,-2.59714182913288E-3 ,-1.53290701533799E-2 ,-2.75110262199412E-2 ,-3.89798143361773E-2
DATA -4.95863679901577E-2 ,-.059197495512273 ,-.06769737170178 ,-7.49887602068642E-2 ,-8.09939552968595E-2 ,-8.56554356109361E-2 ,-8.89362264549138E-2 ,-.090819971192986 ,-9.13107161909428E-2 ,-9.04324175603358E-2 ,-8.82281815794658E-2 ,-8.47592540804446E-2 ,-8.01037772486475E-2 ,-7.43553351423367E-2 ,-6.76213117712769E-2 ,-6.00210877438072E-2
DATA -5.16841032773653E-2 ,-4.27478167486482E-2 ,-3.33555889229312E-2 ,-2.36545235399083E-2 ,-1.37932950439433E-2 ,-3.91999393392034E-3 , 5.81998051829323E-3 , 1.52859515560646E-2 , .024343893110078 , 3.28682295854111E-2 , 4.07434841707331E-2 , 4.78657550406853E-2 , 5.41440015367571E-2 , 5.95011253358703E-2 , 6.38748347064068E-2 , 6.72182831637032E-2
DATA 6.95004771250992E-2 , 7.07064504819803E-2 , 7.08372073065202E-2 , 6.99094371484411E-2 , 6.79550105078911E-2 , 6.50202650522969E-2 , 6.11650959381815E-2 , 5.64618661668915E-2 , 5.09941552129774E-2 , 4.48553661866093E-2 , .038147213502212 , 3.09781144044374E-2 , .023461508734477 , 1.57141319943974E-2 , 7.85426707962836E-3
FOR I=1 TO NUM
LET LOUT(I)=LUT(LIN(I)*127+128)
LET ROUT(I)=LUT(RIN(I)*127+128)
NEXT I
---------------------------------------------------------------
DATA -.997198879551821 ,-.994397759103641 ,-.991596638655462 ,-.988795518207283 ,-.985994397759104 ,-.983193277310924 ,-.980392156862745 ,-.977591036414566 ,-.974789915966387 ,-.971988795518207 ,-.969187675070028 ,-.966386554621849 ,-.963585434173669 ,-.96078431372549 ,-.957983193277311 ,-.955182072829132
DATA -.952380952380953 ,-.949579831932773 ,-.946778711484594 ,-.943977591036415 ,-.941176470588235 ,-.938375350140056 ,-.935574229691877 ,-.932773109243698 ,-.929971988795518 ,-.927170868347339 ,-.92436974789916 ,-.92156862745098 ,-.918767507002801 ,-.915966386554622 ,-.913165266106443 ,-.910364145658263
DATA -.907563025210084 ,-.904761904761905 ,-.901960784313726 ,-.899159663865546 ,-.896358543417367 ,-.893557422969188 ,-.890756302521008 ,-.887955182072829 ,-.88515406162465 ,-.882352941176471 ,-.879551820728291 ,-.876750700280112 ,-.873949579831933 ,-.871148459383753 ,-.868347338935574 ,-.865546218487395
DATA -.862745098039216 ,-.859943977591036 ,-.857142857142857 ,-.854341736694678 ,-.851540616246499 ,-.848739495798319 ,-.84593837535014 ,-.843137254901961 ,-.840336134453782 ,-.837535014005602 ,-.834733893557423 ,-.831932773109244 ,-.829131652661064 ,-.826330532212885 ,-.823529411764706 ,-.820728291316527
DATA -.817927170868347 ,-.815126050420168 ,-.812324929971989 ,-.80952380952381 ,-.80672268907563 ,-.803921568627451 ,-.801120448179272 ,-.798319327731092 ,-.795518207282913 ,-.792717086834734 ,-.789915966386555 ,-.787114845938375 ,-.784313725490196 ,-.781512605042017 ,-.778711484593838 ,-.775910364145658
DATA -.773109243697479 ,-.7703081232493 ,-.76750700280112 ,-.764705882352941 ,-.761904761904762 ,-.759103641456583 ,-.756302521008403 ,-.753501400560224 ,-.750700280112045 ,-.747899159663865 ,-.745098039215686 ,-.742296918767507 ,-.739495798319328 ,-.736694677871148 ,-.733893557422969 ,-.73109243697479
DATA -.728291316526611 ,-.725490196078431 ,-.722689075630252 ,-.719887955182073 ,-.717086834733894 ,-.714285714285714 ,-.686274509803921 ,-.658263305322129 ,-.630252100840336 ,-.602240896358543 ,-.574229691876751 ,-.546218487394958 ,-.518207282913165 ,-.490196078431372 ,-.46218487394958 ,-.434173669467787
DATA -.406162464985995 ,-.378151260504202 ,-.350140056022409 ,-.322128851540616 ,-.294117647058824 ,-.266106442577031 ,-.238095238095238 ,-.210084033613445 ,-.182072829131653 ,-.15406162464986 ,-.126050420168067 ,-9.80392156862746E-2 ,-7.00280112044819E-2 ,-4.20168067226889E-2 ,-1.40056022408963E-2 , 1.40056022408963E-2
DATA 4.20168067226889E-2 , 7.00280112044815E-2 , 9.80392156862741E-2 , .126050420168068 , .15406162464986 , .182072829131653 , .210084033613445 , .238095238095238 , .266106442577031 , .294117647058823 , .322128851540616 , .350140056022409 , .378151260504202 , .406162464985995 , .434173669467787 , .46218487394958
DATA .490196078431372 , .518207282913165 , .546218487394958 , .574229691876751 , .602240896358544 , .630252100840336 , .658263305322129 , .686274509803921 , .714285714285714 , .717086834733893 , .719887955182073 , .722689075630252 , .725490196078431 , .728291316526611 , .73109243697479 , .733893557422969
DATA .736694677871148 , .739495798319328 , .742296918767507 , .745098039215686 , .747899159663866 , .750700280112045 , .753501400560224 , .756302521008403 , .759103641456583 , .761904761904762 , .764705882352941 , .76750700280112 , .7703081232493 , .773109243697479 , .775910364145658 , .778711484593838
DATA .781512605042017 , .784313725490196 , .787114845938375 , .789915966386555 , .792717086834734 , .795518207282913 , .798319327731092 , .801120448179272 , .803921568627451 , .80672268907563 , .80952380952381 , .812324929971989 , .815126050420168 , .817927170868347 , .820728291316527 , .823529411764706
DATA .826330532212885 , .829131652661064 , .831932773109244 , .834733893557423 , .837535014005602 , .840336134453782 , .843137254901961 , .84593837535014 , .848739495798319 , .851540616246499 , .854341736694678 , .857142857142857 , .859943977591036 , .862745098039216 , .865546218487395 , .868347338935574
DATA .871148459383753 , .873949579831933 , .876750700280112 , .879551820728291 , .882352941176471 , .88515406162465 , .887955182072829 , .890756302521008 , .893557422969188 , .896358543417367 , .899159663865546 , .901960784313726 , .904761904761905 , .907563025210084 , .910364145658263 , .913165266106443
DATA .915966386554622 , .918767507002801 , .92156862745098 , .92436974789916 , .927170868347339 , .929971988795518 , .932773109243698 , .935574229691877 , .938375350140056 , .941176470588235 , .943977591036415 , .946778711484594 , .949579831932773 , .952380952380953 , .955182072829132 , .957983193277311
DATA .96078431372549 , .963585434173669 , .966386554621849 , .969187675070028 , .971988795518207 , .974789915966387 , .977591036414566 , .980392156862745 , .983193277310924 , .985994397759104 , .988795518207283 , .991596638655462 , .994397759103641 , .997198879551821 , 1
---------------------------------------------------------------
LET THRESHOLD=.2
FOR K=1 TO NUM
IF ABS(LIN(K))<THRESHOLD THEN ! コンプレッサー
LET LOUT(K)=SGN(LIN(K))*INTERPOLATE(ABS(LIN(K)),0,THRESHOLD,0,.8)
ELSE
LET LOUT(K)=SGN(LIN(K))*INTERPOLATE(ABS(LIN(K)),THRESHOLD,1,.8,1)
END IF
IF ABS(RIN(K))<THRESHOLD THEN
LET ROUT(K)=SGN(RIN(K))*INTERPOLATE(ABS(RIN(K)),0,THRESHOLD,0,.8)
ELSE
LET ROUT(K)=SGN(RIN(K))*INTERPOLATE(ABS(RIN(K)),THRESHOLD,1,.8,1)
END IF
NEXT K
EXTERNAL FUNCTION INTERPOLATE(X,XMIN,XMAX,YMIN,YMAX) ! XMIN<=X<=XMAX
LET X=MIN(XMAX,MAX(X,XMIN))
LET INTERPOLATE=(X-XMIN)*(YMAX-YMIN)/(XMAX-XMIN) + YMIN
END FUNCTION
---------------------------------------------------------------
LET N=32 ! 次数(偶数)
DIM COEF(0 TO N)
LET FILTER=2
LET FREQ=.5
FOR K=1 TO NUM ! オートワウ、ワウワウ
LET FE=2000+800*SIN(FREQ/SAMPLINGFREQ*K*2*PI) ! LFO(低周波発振器)
SELECT CASE FILTER
CASE 0
CALL GETCOEFFICIENTLPF(FE,SAMPLINGFREQ,N,COEF)
CASE 1
CALL GETCOEFFICIENTHPF(FE,SAMPLINGFREQ,N,COEF)
CASE 2
CALL GETCOEFFICIENTBPF(FE,FE+500,SAMPLINGFREQ,N,COEF)
END SELECT
LET L=0
LET R=0
FOR J=0 TO N
IF K+J<=NUM THEN
LET L=L+LIN(K+J)*COEF(J)
LET R=R+RIN(K+J)*COEF(J)
END IF
NEXT J
LET LOUT(K)=L
LET ROUT(K)=R
NEXT K
---------------------------------------------------------------
画像処理でいうガラス加工
LET N=64
FOR K=1 TO NUM STEP N
FOR I=0 TO N-1
LET LOUT(K+I)=LIN(K+N-I) ! 入れ替え
LET ROUT(K+I)=RIN(K+N-I)
NEXT I
NEXT K
---------------------------------------------------------------
画像処理でいう点画
RANDOMIZE
LET N=32
FOR K=1 TO NUM
DO
LET P=INT((RND-.5)*N)
LOOP UNTIL K+P<=NUM AND K+P>=1
LET LOUT(K)=LIN(K+P) ! 乱数入れ替え
LET ROUT(K)=RIN(K+P)
NEXT K
---------------------------------------------------------------
LET SIZE=44100*180
DIM LIN1(SIZE),RIN1(SIZE),LOUT(2*SIZE),ROUT(2*SIZE)
DIM LIN2(SIZE),RIN2(SIZE)
FILE GETOPENNAME F$,"読み込み1 WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL READWAV(F$,NUM1,CHANNEL,SAMPLINGFREQ1,LIN1,RIN1,ERR)
IF ERR>0 THEN STOP
FILE GETOPENNAME F$,"読み込み2 WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL READWAV(F$,NUM2,CHANNEL,SAMPLINGFREQ2,LIN2,RIN2,ERR)
IF ERR>0 THEN STOP
IF SAMPLINGFREQ1<>SAMPLINGFREQ2 THEN
PRINT "サンプリング周波数が違います"
STOP
END IF
FOR K=1 TO NUM1 ! ファイル連結
LET N=N+1
LET LOUT(N)=LIN1(K)
LET ROUT(N)=RIN1(K)
NEXT K
FOR K=1 TO NUM2
LET N=N+1
LET LOUT(N)=LIN2(K)
LET ROUT(N)=RIN2(K)
NEXT K
---------------------------------------------------------------
https://ja.wikipedia.org/wiki/平均
https://ja.wikipedia.org/wiki/ヘルダー平均
IF SAMPLINGFREQ1<>SAMPLINGFREQ2 THEN
PRINT "サンプリング周波数が違います"
STOP
END IF
LET NN=MAX(NUM1,NUM2)
LET MODE=0
FOR K=1 TO NN
IF K<=NUM1 AND K<=NUM2 THEN ! ファイルミックス(ファイル合成)
SELECT CASE MODE
CASE 0
LET LOUT(K)=(LIN1(K)+LIN2(K))/2 ! 相加平均
LET ROUT(K)=(RIN1(K)+RIN2(K))/2
CASE 1
LET LOUT(K)=MAX(LIN1(K),LIN2(K))
LET ROUT(K)=MAX(RIN1(K),RIN2(K))
CASE 2
LET LOUT(K)=MIN(LIN1(K),LIN2(K))
LET ROUT(K)=MIN(RIN1(K),RIN2(K))
CASE 3
LET LOUT(K)=(LIN1(K)-LIN2(K))
LET ROUT(K)=(RIN1(K)-RIN2(K))
CASE 4
LET LOUT(K)=SGN_(LIN1(K))*SGN_(LIN2(K))*SQR(ABS(LIN1(K)*LIN2(K))) ! 相乗平均
LET ROUT(K)=SGN_(RIN1(K))*SGN_(RIN2(K))*SQR(ABS(RIN1(K)*RIN2(K)))
CASE 5
IF LIN1(K)=0 OR LIN2(K)=0 THEN
LET LOUT(K)=0
ELSE
LET LOUT(K)=SGN_(LIN1(K))*SGN_(LIN2(K))/(ABS(1/LIN1(K))+ABS(1/LIN2(K))) ! 調和平均 1/(1/M+1/N)=N*M/(N+M)
END IF
IF RIN1(K)=0 OR RIN2(K)=0 THEN
LET ROUT(K)=0
ELSE
LET ROUT(K)=SGN_(RIN1(K))*SGN_(RIN2(K))/(ABS(1/RIN1(K))+ABS(1/RIN2(K)))
END IF
CASE 6
LET LOUT(K)=SGN_(LIN1(K))*SGN_(LIN2(K))*SQR(LIN1(K)^2+LIN2(K)^2)/2 ! 2乗平均
LET ROUT(K)=SGN_(RIN1(K))*SGN_(RIN2(K))*SQR(RIN1(K)^2+RIN2(K)^2)/2
CASE 7
LET M=2.5
LET N=3.5
LET LOUT(K)=SGN_(LIN1(K))*SGN_(LIN2(K))*(ABS(LIN1(K))^M+ABS(LIN2(K))^N)^(2/(M+N)) ! ミンコフスキー距離(ヘルダー平均)
LET ROUT(K)=SGN_(RIN1(K))*SGN_(RIN2(K))*(ABS(RIN1(K))^M+ABS(RIN2(K))^N)^(2/(M+N))
! LET LOUT(K)=SGN_(LIN1(K))*SGN_(LIN2(K))*(ABS(LIN1(K))^(1/M)+ABS(LIN2(K))^(1/N))^(2*N*M/(M+N))
! LET ROUT(K)=SGN_(RIN1(K))*SGN_(RIN2(K))*(ABS(RIN1(K))^(1/M)+ABS(RIN2(K))^(1/N))^(2*N*M/(M+N))
CASE 8
LET LOUT(K)=PXOR(ABS(LIN1(K)),ABS(LIN2(K)))*SGN_(LIN1(K))*SGN_(LIN2(K)) ! XOR
LET ROUT(K)=PXOR(ABS(RIN1(K)),ABS(RIN2(K)))*SGN_(RIN1(K))*SGN_(RIN2(K))
CASE 9
LET LOUT(K)=PEQV(ABS(LIN1(K)),ABS(LIN2(K)))*SGN_(LIN1(K))*SGN_(LIN2(K)) ! EQV
LET ROUT(K)=PEQV(ABS(RIN1(K)),ABS(RIN2(K)))*SGN_(RIN1(K))*SGN_(RIN2(K))
CASE 10
LET LOUT(K)=PIMP(ABS(LIN1(K)),ABS(LIN2(K)))*SGN_(LIN1(K))*SGN_(LIN2(K)) ! IMP
LET ROUT(K)=PIMP(ABS(RIN1(K)),ABS(RIN2(K)))*SGN_(RIN1(K))*SGN_(RIN2(K))
CASE 11
LET LOUT(K)=PNOR(ABS(LIN1(K)),ABS(LIN2(K)))*SGN_(LIN1(K))*SGN_(LIN2(K)) ! NOR
LET ROUT(K)=PNOR(ABS(RIN1(K)),ABS(RIN2(K)))*SGN_(RIN1(K))*SGN_(RIN2(K))
CASE 12
LET LOUT(K)=PNAND(ABS(LIN1(K)),ABS(LIN2(K)))*SGN_(LIN1(K))*SGN_(LIN2(K)) ! NAND
LET ROUT(K)=PNAND(ABS(RIN1(K)),ABS(RIN2(K)))*SGN_(RIN1(K))*SGN_(RIN2(K))
CASE 13
LET LOUT(K)=PNIMP(ABS(LIN1(K)),ABS(LIN2(K)))*SGN_(LIN1(K))*SGN_(LIN2(K)) ! NIMP
LET ROUT(K)=PNIMP(ABS(RIN1(K)),ABS(RIN2(K)))*SGN_(RIN1(K))*SGN_(RIN2(K))
END SELECT
ELSEIF K<=NUM2 AND K>NUM1 THEN
LET LOUT(K)=LIN2(K)
LET ROUT(K)=RIN2(K)
ELSEIF K<=NUM1 AND K>NUM2 THEN
LET LOUT(K)=LIN1(K)
LET ROUT(K)=RIN1(K)
END IF
NEXT K
---------------------------------------------------------------
IF CHANNEL<>2 THEN
PRINT "ステレオではありません"
STOP
END IF
CALL WRITEWAV("左チャンネル.wav",NUM,SAMPLINGFREQ,16,LOUT) ! ステレオ分解 モノラル出力
CALL WRITEWAV("右チャンネル.wav",NUM,SAMPLINGFREQ,16,ROUT)
END
---------------------------------------------------------------
INPUT PROMPT "分割点(秒)=":PLAYTIME
LET NN=SAMPLINGFREQ*PLAYTIME
FOR K=1 TO NN
LET LOUT(K)=LIN(K)
LET ROUT(K)=RIN(K)
NEXT K
CALL WRITEWAV("分割1.wav",NN,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT,ROUT) ! ファイル分割
MAT LOUT=ZER
MAT ROUT=ZER
FOR K=NN+1 TO NUM
LET N=N+1
LET LOUT(N)=LIN(K)
LET ROUT(N)=RIN(K)
NEXT K
CALL WRITEWAV("分割2.wav",N,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT,ROUT)
END
コンソールアプリ - しばっち
2024/10/13 (Sun) 07:39:33
コンソールアプリ
ffmpeg
プログラムで読み込むためのwavファイルを予め変換しておくのは意外とわずらわしい作業かと思います。
既に幾つかの適当なファイルをお持ちなら、その場で利用したいファイルを決めたいかと思います。
そこでお薦めなのがffmpegです。
https://www.ffmpeg.org/
https://www.otsuka-bs.co.jp/web-creation/blog/archive/20231011-02.html
https://jp.videoproc.com/edit-convert/ffmpeg-guide-for-beginners.htm
コンソールアプリなのでコマンドプロンプトから次のように打ち込むと
ffmpeg -i sample.mp3 sample.wav
これでmp3からwavに変換できます。動画ファイルからでも変換可能で大抵の音楽、動画ファイル形式に対応しています。
ですが、いちいちキータイプするのも面倒なので下記のようにすればGUI化できます。
サンプリング周波数44100Hz 16ビットのwavファイルに変換します。
ffmpeg -h でヘルプ表示します。
「スタートボタン」の「すべてのアプリ」の「ターミナル」からWindows PowerShellを起動した場合は、「cmd」と打ち込んでください。
コマンドプロンプトが起動します。「c:」や「d:」でドライブ間を移動できます。
「cd フォルダ名」でフォルダ間を移動できます。「dir」でフォルダ・ファイル名を表示します。
「exit」で終了します。詳しくはネット検索してください。
エクスプローラのアドレスバーをクリックして「cmd」と打ち込むとコマンドプロンプトが起動します。
下記を実行するとコンソールウィンドゥーが開きますが
かなりうざいのでコンソールウィンドゥーを隠すオプションが欲しいところです。(STARTコマンドでウィンドゥー隠せる?)
EXECUTE "~" WITH ("~"),HIDDEN
但し、コンソール内でアプリがエラー停止(フリーズ)した時コンソールウィンドゥーが閉じれなくなってしまう??? つまり十進BASICが終了できなくなる?
FILE GETOPENNAME F$,"音楽・動画ファイル |*.*"
IF F$="" THEN STOP
LET TEMP$="temporary.wav" ! パスを指定。作業用wavファイル
EXECUTE "ffmpeg.exe" WITH ("-i",F$,"-f","wav","-c:a","pcm_s16le","-vn","-ar","44100",TEMP$) ! ffmpegのパスを指定。
CALL READWAV(TEMP$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN,ERR)
IF ERR>0 THEN STOP
これでシームレスに作業できます。
FILE DELETE TEMP$ をプログラム最後に置けば後始末もできます。
-------------------------------------------------------------------------------------------------
ファイル再生
ffplay(ffmpegに同梱)による再生
大抵の音楽・動画ファイルを再生可能
FILE GETOPENNAME F$,"ファイル読み込み |*.*"
IF F$="" THEN STOP
EXECUTE "ffplay.exe" WITH("-autoexit","-exitonkeydown","-exitonmousedown",F$) ! ffplayのパスを指定(ffmpegと同じはず)
END
-------------------------------------------------------------------------------------------------
sox
https://sourceforge.net/projects/sox/
https://qiita.com/_atsushisakai/items/02e404aa26d9a62f1b4f
https://aiyumi.github.io/ja/blog/sox-basic-intro/
https://jeremylee.sh/bins/
soxもコンソールアプリでファイル変換ができます。
但しWindows版ではmp3を直接扱えず別途ライブラリーが必要なようです。
https://qiita.com/constdrop/items/74bcaa171270dcb9bf19
https://stackoverflow.com/questions/3537155/sox-fail-util-unable-to-load-mad-decoder-library-libmad-function-mad-stream
コンソールアプリなのでコマンドプロンプトから次のように打ち込むと
sox sample.ogg sample.wav
oggからwavファイルに変換できます。
sox -h でヘルプ表示します。
http://www.xucker.jpn.org/pc/sox_raw.html
https://p--q.blogspot.com/2015/03/soxsound-exchange1.html
https://blog.asial.co.jp/885/
LET TEMP$="temporary.wav" ! パスを指定。作業用wavファイル
FILE GETOPENNAME F$,"対応 ファイル|*.wav;*.ogg;*.aiff;*.mp3;*.snd;*.au;*.flac;*.raw"
IF F$="" THEN STOP
EXECUTE "sox.exe" WITH (F$,TEMP$) ! ファイル変換 パスを指定
FILE DELETE TEMP$ をプログラム最後に置けば後始末もできます。
-------------------------------------------------------------------------------------------------
再生もできます。
FILE GETOPENNAME F$,"対応 ファイル|*.wav;*.ogg;*.aiff;*.mp3;*.snd;*.au;*.flac;*.raw"
IF F$="" THEN STOP
EXECUTE "sox.exe" WITH (F$,"-t","waveaudio") ! 演奏 パスを指定
END
-------------------------------------------------------------------------------------------------
スペクトル表示
LET TEMP$="spectrogram.png"
FILE GETOPENNAME F$,"対応 ファイル|*.wav;*.ogg;*.aiff;*.mp3;*.snd;*.au;*.flac;*.raw"
IF F$="" THEN STOP
EXECUTE "sox.exe" WITH (F$,"-n","spectrogram","-o",TEMP$) ! パスを指定
GLOAD TEMP$
END
その他色々なことができるようです。
-------------------------------------------------------------------------------------------------
Windowsユーザーならみんな持ってるウィンドーズメディアプレイヤーによる動画・音楽再生
非Windows系ファイルには未対応なポンコツプレイヤー? aiff,au形式には未対応
FILE GETOPENNAME F$,"ファイル読み込み |*.*"
IF F$="" THEN STOP
EXECUTE "C:\Program Files\Windows Media Player\wmplayer.exe" WITH(F$)
END
-------------------------------------------------------------------------------------------------
VLCメディアプレイヤーによる再生
https://www.videolan.org/vlc/index.ja.html
大抵の音楽・動画ファイルが再生ができます。
FILE GETOPENNAME F$,"ファイル読み込み |*.*"
IF F$="" THEN STOP
EXECUTE "C:\Program Files\VideoLAN\VLC\VLC.EXE" WITH(F$)
END
Re: コンソールアプリ - しばっち
2024/10/13 (Sun) 07:40:51
C/C++ライブラリーによるコンソールアプリでwavファイルからcsvファイルを書き出します。
https://www.un4seen.com/
これはDLL化には失敗した(初期化に失敗。原因不明)ものの、wavファイル以外にもmp3を直接読み込めるので作成しました。
その他mod形式と呼ばれるitやs3mファイル等にも対応しているようですがよくわかりません。
実行には別途BASS.DLLが必要です。
csvファイルなのでエクセル等でも読み込めます。
wav2csv.exeはwin32版です。win2csv64.exeはwin64版になります。
コマンドプロンプトから
wav2csv test.wav 標準出力へ書き出し。
wav2csv input.wav sample.csv wavファイルからcsvファイルへ書き出し。
wav2csv input.mp3 sample.csv 3 5 mp3ファイルの3秒から5秒までを切り出してcsvファイル化
-1~1の正規値を出力します。
マルチチャンネル出力可能ですが拡張フォーマットには対応していないようです。
VC++2022でコンパイルしました。
下記からダウンロードしてください。(wave.zip)
https://66.gigafile.nu/0121-d5d86eb73a1f6ce256c440f69c9462329
ダウンロード期限:2025年1月21日(火)
パスワード:設定していません
----------------------------------------------------------------------------------------
wav2csv.cpp
#include <cstdlib>
#include <cstdio>
#include "bass.h"
#include <cmath>
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#pragma comment(lib,"bass.lib")
using namespace std;
int main(int argc, char *argv[])
{
BASS_CHANNELINFO info;
DWORD chan,bpf,p;
QWORD pos;
double secs;
int n=0,no,samplebit,i,j,flg=0;
double starttime=-1.0,endtime=-1.0;
char *wavname,*csvname;
if (argc==1) return 1;
if (argc>=2) wavname=argv[1];
if (argc>=3) {
csvname=argv[2];
flg=1;
}
if (argc>=4) starttime=atof(argv[3]);
if (argc==5) endtime=atof(argv[4]);
if (!BASS_Init(-1, 44100, 0, 0, NULL)) return 1;
chan = BASS_StreamCreateFile(FALSE, wavname, 0, 0, BASS_STREAM_DECODE);
if (!chan && BASS_ErrorGetCode() == BASS_ERROR_FILEFORM) {
chan=BASS_MusicLoad(FALSE,wavname,0,0,BASS_MUSIC_DECODE | BASS_MUSIC_RAMPS | BASS_MUSIC_PRESCAN,0);
}
if(!chan) {
BASS_Free();
return 1;
}
BASS_ChannelGetInfo(chan,&info);
samplebit=(info.flags & BASS_SAMPLE_8BITS ? 8 : 16);
bpf=info.chans*(info.flags & BASS_SAMPLE_8BITS ? 1 : 2);
pos=BASS_ChannelGetLength(chan,BASS_POS_BYTE);
if(pos==0) {
BASS_Free();
return 1;
} else {
secs=BASS_ChannelBytes2Seconds(chan,pos);
}
if(starttime>=0.0) if (!BASS_ChannelSetPosition(chan, starttime * bpf, BASS_POS_BYTE))
{
BASS_Free();
return 1;
}
if(starttime<endtime && endtime>0.0) if (!BASS_ChannelSetPosition(chan, endtime * bpf, BASS_POS_END))
{
BASS_Free();
return 1;
}
if (flg==0) {
cout << setprecision(15) << info.freq << endl; // サンプリング周波数
cout << setprecision(15) << samplebit << endl; // サンプルビット
cout << setprecision(15) << info.chans << endl; // チャンネル数
cout << setprecision(15) << pos/bpf << endl; // データ数
} else {
ofstream ofs(csvname);
ofs.precision(15);
ofs << info.freq << endl; // サンプリング周波数
ofs << samplebit << endl; // サンプルビット
ofs << info.chans << endl; // チャンネル数
ofs << pos/bpf << endl; // データ数
}
while (1) {
short buf[10000];
ofstream ofs(csvname, std::ios::out | std::ios::app);
ofs.precision(15);
int c=BASS_ChannelGetData(chan,buf,sizeof(buf));
if (c==-1) break;
for (i=0; i<c; i+=info.chans)
for(j=0; j<info.chans; j++) {
if (flg==0) cout << setprecision(15) << (double)buf[i+j]/pow(2.0,samplebit-1);
else {
ofs << (double)buf[i+j]/pow(2.0,samplebit-1);
}
if (j<info.chans-1) {
if (flg==0) cout << ",";
else ofs << ",";
}
else {
if (flg==0) cout << endl;
else ofs << endl;
}
}
}
BASS_Free();
return 0;
}
----------------------------------------------------------------------------------------
使用例
下記のようにするとGUI化できます。
FILE GETOPENNAME F$,"読み込み 対応ファイル|*.wav;*.aiff;*.mp3;*.mp2;*.mp1;*.ogg;*.mo3;*.it;*.s3m;*.mtm;*.mod;*.umx;*.xm"
IF F$="" THEN STOP
LET TEMP$="temporary.csv"
LET STARTTIME=-1 ! 負数では無効。STARTTIME>=0で有効。秒数指定
LET ENDTIME=-1 ! 負数で無効。ENDTIME>0 STARTTIME<ENDTIME で有効
EXECUTE "wav2csv.exe" WITH (F$,TEMP$) ! パスを指定。
!!EXECUTE "wav2csv.exe" WITH (F$,TEMP$,STARTTIME,ENDTIME)
END
Re: コンソールアプリ - しばっち
2024/10/13 (Sun) 07:41:57
C/C++ライブラリーによるコンソールアプリはwavファイルからcsvファイルを書き出します。
https://github.com/adamstark/AudioFile
ヘッダーライブラリーです。ヘッダーファイルをインクルードするだけで使えます。
上記URLからZIPファイルをダウンロードしてVC++2022で下記cppソースからコンパイルできます。
コマンドプロンプトから
wave2csv sample.wav sample.csv
のように打ち込んでください。
wave2csv.exeはwin32版です。wave2csv64.exeはwin64版になります。
-1~1の正規値を出力します。
VC++2022でコンパイルしました。
マルチチャンネル出力可能ですが拡張フォーマットには対応していないようです。
----------------------------------------------------------------------------------------
wave2csv.cpp
#include "AudioFile.h"
#include <iostream>
#include <fstream>
using namespace std;
int main(int argc,char **argv)
{
AudioFile<double> audioFile;
int samplingfreq,channel,samplebit,num,i,ch;
char *wavname,*csvname;
if (argc!=3) return 1;
wavname=argv[1];
csvname=argv[2];
ofstream csv(csvname,ios::out);
if(!audioFile.load(wavname)) return 1;
samplingfreq = audioFile.getSampleRate();
samplebit = audioFile.getBitDepth();
channel = audioFile.getNumChannels();
num = audioFile.getNumSamplesPerChannel();
ofstream ofs(csvname);
if(!ofs) return 1;
ofs << samplingfreq << endl; // サンプリング周波数
ofs << samplebit << endl; // サンプルビット
ofs << channel << endl; // チャンネル数
ofs << num << endl; // データ数
for (i = 0; i < num; i++) {
for (ch=0; ch<channel; ch++) {
ofs << audioFile.samples[ch][i];
if (ch<channel-1) ofs << ",";
else ofs << endl;
}
}
return 0;
}
----------------------------------------------------------------------------------------
使用例
次のようにするとGUI化できます。
FILE GETOPENNAME F$,"読み込み WAVファイル|*.WAV"
IF F$="" THEN STOP
FILE GETSAVENAME G$,"保存 CSVファイル|*.CSV"
IF G$="" THEN STOP
IF POS(LCASE$(G$),".csv")=0 THEN LET G$=G$&".csv"
EXECUTE "wave2csv.exe" WITH (F$,G$)
END
Re: コンソールアプリ - しばっち
2024/10/13 (Sun) 07:43:15
C/C++ライブラリーによるコンソールアプリはau/sndファイルからcsvファイルを書き出します。
http://www.mega-nerd.com/libsndfile/
コマンドプロンプトから
snd2csv sample.au sample.csv
のように打ち込んでください。
実行には別途libsndfile-1.dllが必要です。
snd2csv.exeはwin32版です。snd2csv64.exeはwin64版になります。
マルチチャンネル出力可能ですが拡張フォーマットには対応していないようです。
VC++2022でコンパイルしました。
----------------------------------------------------------------------------------------
snd2csv.c
#include "sndfile.h"
#include <stdlib.h>
#include <stdio.h>
#include <float.h>
#define BLOCK_SIZE 4096
int main(int argc,char **argv)
{
char *wavname,*csvname;
SNDFILE *sfr;
SF_INFO sfinfo;
int i,ch,samplingfreq,num,channel,frames,readcount;
double *data;
FILE *ofs;
if (argc!=3) return 1;
wavname=argv[1];
csvname=argv[2];
if(!(sfr = sf_open(wavname, SFM_READ, &sfinfo))) return 2;
samplingfreq=sfinfo.samplerate;
channel=sfinfo.channels;
num=sfinfo.frames/channel;
ofs=fopen(csvname,"w");
if(ofs==NULL) return 1;
fprintf(ofs,"%d \n",samplingfreq); // サンプリング周波数
fprintf(ofs,"%d \n",16); // サンプルビット
fprintf(ofs,"%d \n",channel); // チャンネル数
fprintf(ofs,"%d \n",num); // データ数
data=(double *)malloc(BLOCK_SIZE*sizeof(double));
if (data==NULL) return 4;
frames=BLOCK_SIZE/channel;
while((readcount=(int)sf_read_double(sfr,data,frames))>0)
{
for (i=0; i<readcount; i++) {
for (ch=0; ch<channel; ch++) {
fprintf(ofs,"%18.15f",data[i*channel+ch]);
if (ch<channel-1) fprintf(ofs,",");
else fprintf(ofs,"\n");
}
}
}
sf_close(sfr);
fclose(ofs);
free(data);
return 0;
}
Re: コンソールアプリ - しばっち
2024/10/13 (Sun) 07:44:31
C/C++ライブラリーによるコンソールアプリはwavファイルからcsvファイルを書き出します。
https://github.com/DIYFXWorld/Other
ヘッダーライブラリーです。ヘッダーファイルをインクルードするだけで使えます。
上記URLからダウンロードしてVC++2022で下記cppソースからコンパイルできます。
コマンドプロンプトから
wave2csv sample.wav sample.csv
のように打ち込んでください。
wavetocsv.exeはwin32版です。wavetocsv64.exeはwin64版になります。
-1~1の正規値を出力します。モノラル、ステレオ出力のみです。
VC++2022でコンパイルしました。
----------------------------------------------------------------------------------------
wavetocsv.cpp
#include "wave.hpp"
#include <fstream>
#include <iomanip>
using namespace std;
int main(int argc,char **argv)
{
int i,samplingfreq,channel,num;
char *csvname,*wavname,comma;
wave<double> src;
if (argc!=3) return 1;
wavname=argv[1];
csvname=argv[2];
load(wavname,src);
samplingfreq=src.fs;
num=src.length;
channel=src.channel;
ofstream ofs(csvname);
if(!ofs) return 1;
ofs.precision(15);
ofs << samplingfreq << endl; // サンプリング周波数
ofs << "16" << endl; // サンプルビット
ofs << channel << endl; // チャンネル数
ofs << num << endl; // データ数
for (i = 0; i < num; i++) {
if(channel==1) ofs << src[i] << endl;
if(channel==2) ofs << src.L[i] << "," << src.R[i] << endl;
}
return 0;
}
Re: コンソールアプリ - しばっち
2024/10/13 (Sun) 07:45:33
C/C++ライブラリーによるコンソールアプリでwavファイルからcsvファイルを書き出します。
https://github.com/Numerix-DSP/wav_file
ヘッダーライブラリーです。ヘッダーファイルをインクルードするだけで使えます。
上記URLからダウンロードしてVC++2022で下記cppソースからコンパイルできます。
コマンドプロンプトから
wavcsv sample.wav sample.csv
のように打ち込んでください。
wavcsv.exeはwin32版です。wavcsv64.exeはwin64版になります。
マルチチャンネル出力可能ですが拡張フォーマットには対応していないようです。
VC++2022でコンパイルしました。
----------------------------------------------------------------------------------------
wavcsv.c
#include <stdio.h>
#include <stdlib.h>
#include "wav_file.h"
#include <math.h>
int main(int argc,char **argv)
{
FILE *fpwav,*fpcsv;
int samplingfreq,channel,samplebit,num,count;
char *wavname,*csvname;
double *dat;
WAV_FILE_INFO wavinfo;
if (argc=!3) return 1;
wavname=argv[1];
csvname=argv[2];
if ((fpwav=fopen(wavname,"rb"))==NULL) return 1;
wavinfo=wav_read_header(fpwav);
if (wavinfo.NumberOfChannels == 0) return 1;
num=wavinfo.NumberOfSamples;
dat=(double *)malloc(sizeof(double)*num);
if (dat==NULL) return 1;
channel=wavinfo.NumberOfChannels;
samplingfreq=wavinfo.SampleRate;
samplebit=wavinfo.WordLength;
if((fpcsv=fopen(csvname,"w"))==NULL) return 1;
fprintf(fpcsv,"%d\n",samplingfreq);
fprintf(fpcsv,"%d\n",samplebit);
fprintf(fpcsv,"%d\n",channel);
fprintf(fpcsv,"%d\n",num/channel);
while ((count = (int)wav_read_data (dat, fpwav, wavinfo, num)) == num) {
for (int i = 0; i < count/channel; i++) {
for(int ch=0; ch<channel; ch++) {
fprintf(fpcsv,"%.15lf ", dat[i*channel+ch]/pow(2.0,samplebit-1));
if(ch<channel-1) fprintf(fpcsv,",");
}
fprintf(fpcsv,"\n");
}
}
fclose(fpwav);
fclose(fpcsv);
free(dat);
return 0;
}
Re: コンソールアプリ - しばっち
2024/10/13 (Sun) 07:47:08
wavファイルを読み込みます。
マルチチャンネル対応のため一部仕様を変更しています。
EXTERNAL SUB READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT(,),ERR)
OPTION CHARACTER BYTE
DIM A$(40)
LET ERR=0
WHEN EXCEPTION IN
OPEN #1:NAME F$,ACCESS INPUT !'wavファイル読み込み
USE
LET ERR=2
CLOSE #1
EXIT SUB
END WHEN
FOR I=1 TO 12
CHARACTER INPUT #1:A$(I)
NEXT I
IF A$(1)&A$(2)&A$(3)&A$(4)<>"RIFF" THEN
LET ERR=1
!PRINT "WAVファイルではありません"
CLOSE #1
EXIT SUB
END IF
LET WAVEFILESIZE=INT32(A$(5)&A$(6)&A$(7)&A$(8))
IF A$(9)&A$(10)&A$(11)&A$(12)<>"WAVE" THEN
LET ERR=1
PRINT "WAVファイルではありません"
CLOSE #1
EXIT SUB
END IF
DO
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
SELECT CASE A$(1)&A$(2)&A$(3)&A$(4)
CASE "fmt "
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET HEADERSIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
FOR I=1 TO HEADERSIZE
CHARACTER INPUT #1:A$(I)
NEXT I
IF HEADERSIZE=16 OR HEADERSIZE=18 THEN ! 標準フォーマット
LET WAVETYPE=INT16(A$(1)&A$(2))
LET CHANNEL=INT16(A$(3)&A$(4))
LET SAMPLINGFREQ=INT32(A$(5)&A$(6)&A$(7)&A$(8))
LET DATARATE=INT32(A$(9)&A$(10)&A$(11)&A$(12))
LET SAMPLESIZE=INT16(A$(13)&A$(14))
LET SAMPLEBIT=INT16(A$(15)&A$(16))
IF HEADERSIZE=18 THEN LET CBSIZE=INT16(A$(17)&A$(18))
ELSEIF HEADERSIZE=40 THEN ! 拡張フォーマット
LET TMP=INT16(A$(1)&A$(2))
LET CHANNEL=INT16(A$(3)&A$(4))
LET SAMPLINGFREQ=INT32(A$(5)&A$(6)&A$(7)&A$(8))
LET COMPRESS=INT32(A$(9)&A$(10)&A$(11)&A$(12)) ! SAMPLINGFREQ*BLOCKSIZE
LET SAMPLESIZE=INT16(A$(13)&A$(14)) ! SAMPLEBIT/8*CHANNEL
LET SAMPLEBIT=INT16(A$(15)&A$(16))
LET CBSIZE=INT16(A$(17)&A$(18))
LET BITPERSAMPLE=INT16(A$(19)&A$(20))
LET CHANNELMASK=INT32(A$(21)&A$(22)&A$(23)&A$(24))
ELSE
LET ERR=2
CLOSE #1
EXIT SUB
END IF
CASE "data"
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET PCMSIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
!LET SECOND=PCMSIZE/DATARATE
!' LET NUM=INT(SAMPLINGFREQ*SECOND)
LET NUM=PCMSIZE/SAMPLESIZE
EXIT DO
CASE "fact"
FOR I=1 TO 8
CHARACTER INPUT #1:A$(I)
NEXT I
!' LET SIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
!' LET SAMPLE=INT32(A$(5)&A$(6)&A$(7)&A$(8))
CASE "LIST"
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET SIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
FOR I=1 TO SIZE
CHARACTER INPUT #1:DMY$
NEXT I
CASE "JUNK"
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET SIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
FOR I=1 TO SIZE
CHARACTER INPUT #1:DMY$
NEXT I
CASE ELSE
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET SIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
FOR I=1 TO SIZE
CHARACTER INPUT #1:DMY$
NEXT I
END SELECT
LOOP
!REDIM DAT(CHANNEL,NUM)
LET B$=REPEAT$(CHR$(0),4)
LET A=INT(NUM/100)
PRINT "読み込み中"
FOR K=1 TO NUM
IF MOD(K,INT(NUM/A))=0 AND INT(K/A)<>R THEN
LET R=INT(K/A)
PRINT R;"%"
END IF
FOR CH=1 TO CHANNEL
FOR J=1 TO SAMPLEBIT/8
CHARACTER INPUT #1:B$(J:J)
NEXT J
SELECT CASE SAMPLEBIT
CASE 8
LET DAT(CH,K)=(ORD(B$(1:1))-128)/2^7
CASE 16
LET DAT(CH,K)=INT16(B$(1:2))/2^15
CASE 24
LET DAT(CH,K)=INT24(B$(1:3))/2^23
CASE 32
LET DAT(CH,K)=INT32(B$(1:4))/2^31
END SELECT
NEXT CH
NEXT K
CLOSE #1
END SUB
以下略
--------------------------------------------------------------------------------
csvファイルを書き出します。
マルチチャンネル対応のため一部仕様を変更しています。
EXTERNAL SUB WRITECSV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT(,))
IF F$="" THEN EXIT SUB
IF POS(LCASE$(F$),".csv")=0 THEN LET F$=F$&".csv"
IF NUM=0 THEN LET NUM=UBOUND(DAT,2)
OPEN #1:NAME F$
ERASE #1
PRINT #1:SAMPLINGFREQ
PRINT #1:SAMPLEBIT
PRINT #1:CHANNEL
PRINT #1:NUM
LET A=INT(NUM/100)
PRINT "書き出し中"
FOR K=1 TO NUM
IF MOD(K,INT(NUM/A))=0 AND INT(K/A)<>R THEN
LET R=INT(K/A)
PRINT R;"%"
END IF
FOR CH=1 TO CHANNEL
LET DAT(CH,K)=MIN(1,MAX(DAT(CH,K),-1))
PRINT #1:DAT(CH,K);
IF CH<=CHANNEL-1 THEN PRINT #1:","; ELSE PRINT #1
NEXT CH
NEXT K
CLOSE #1
END SUB
--------------------------------------------------------------------------------
配列のサイズとデータ数が一致している時は下記のようにすると高速に書き込みできます。
マルチチャンネル対応のため一部仕様を変更しています。
EXTERNAL SUB WRITECSV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT(,))
IF F$="" THEN EXIT SUB
IF POS(LCASE$(F$),".csv")=0 THEN LET F$=F$&".csv"
IF NUM=0 THEN LET NUM=UBOUND(DAT,2)
OPEN #1:NAME F$,RECTYPE CSV
ERASE #1
WRITE #1:SAMPLINGFREQ
WRITE #1:SAMPLEBIT
WRITE #1:CHANNEL
WRITE #1:NUM
MAT WRITE #1:DAT
CLOSE #1
END SUB
--------------------------------------------------------------------------------
使用例
マルチチャンネルwavファイルからマルチチャンネルcsvファイルを
書き出します。
コンソールアプリwav2csv.exe等の代替プログラムになります。
LET SIZE=44100*100
LET CH=5
DIM DAT(CH,SIZE)
FILE GETOPENNAME F$,"読み込み WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,DAT,ERR)
IF ERR>0 THEN STOP
FILE GETSAVENAME G$,"保存 CSVファイル|*.csv"
IF G$="" THEN STOP
CALL WRITECSV(G$,NUM,CHANNEL,SAMPLINGFREQ,16,DAT)
END
以下略
Re: コンソールアプリ - しばっち
2024/10/13 (Sun) 07:48:18
C++ライブラリーによるコンソールアプリでcsvファイルからwavファイルを出力します。
https://github.com/adamstark/AudioFile
ヘッダーライブラリーです。ヘッダーファイルをインクルードするだけで使えます。
上記URLからダウンロードしてVC++2022で下記cppソースからコンパイルできます。
コマンドプロンプトから
csv2wave sample.csv output.wav
のように打ち込んでください。
csv2wave.exeはwin32版です。csv2wave64.exeはwin64版になります。
csvファイルのPCMデータ値は-1~1の正規値を入力してください。
この範囲を超えるとクリッピングノイズが発生します。
下記のようなフォーマットのcsvファイルからwavファイルに変換します。
sample.csv
44100 ---> サンプリング周波数(8000,16000,32000,11025,22050,44100,48000,96000等)
16 ---> サンプルビット数(8,16,24,32)
2 ---> チャンネル数 1ch~20ch位 ?
132300 ---> この行以下のPCMデータ数(サンプル数)
2.84797490584979E-2 , 5.68670237962044E-2 ---> PCMデータ 2ch分(左、右) -1~1迄の範囲
5.68670237962044E-2 , .112996053647038
8.50696501583163E-2 , .167658672951382
.112996053647038 , .220145495506271
.140555556665827 , .269775371593091
.167658672951382 , .315904227623731
.194217398137347 , .357933424629859
.220145495506271 , .395317527122704
: :
: : 以下省略
マルチチャンネル入力可能ですが拡張フォーマットには対応していないようです。
VC++2022でコンパイルしました。
下記からダウンロードしてください。(wave.zip)
https://66.gigafile.nu/0121-d5d86eb73a1f6ce256c440f69c9462329
ダウンロード期限:2025年1月21日(火)
パスワード:設定していません
----------------------------------------------------------------------------------------
csv2wave.cpp
#include "AudioFile.h"
#include <fstream>
#include <string>
#include <sstream>
#include <cmath>
#include <vector>
using namespace std;
double range(double x)
{
if (x<-1.0) x=-1.0;
if (x>1.0) x=1.0;
return x;
}
int main(int argc,char **argv)
{
int i,samplingfreq,samplebit,channel,num,ch;
char *csvname,*wavname;
string buf;
AudioFile<double> audioFile;
if (argc!=3) return 1;
csvname=argv[1];
wavname=argv[2];
ifstream csv(csvname,ios::in);
if (!csv) return 1;
csv >> samplingfreq;
csv >> samplebit;
csv >> channel;
csv >> num;
audioFile.setAudioBufferSize (channel, num);
audioFile.setBitDepth (samplebit);
audioFile.setSampleRate (samplingfreq);
string value;
for (int i = 0; i < num; i++)
{
getline(csv,buf);
ch=0;
stringstream ss(buf);
while(getline(ss,value,',')) {
audioFile.samples[ch][i]=stod(value);
ch++;
}
}
if(audioFile.save(wavname, AudioFileFormat::Wave)) return 0;
else return 1;
}
----------------------------------------------------------------------------------------
使用例
次のようにするとGUI化できます。
FILE GETOPENNAME F$,"読み込み CSVファイル|*.CSV"
IF F$="" THEN STOP
FILE GETSAVENAME G$,"保存 WAVファイル|*.WAV"
IF G$="" THEN STOP
IF POS(LCASE$(G$),".wav")=0 THEN LET G$=G$&".wav"
EXECUTE "csv2wave.exe" WITH (F$,G$)
END
Re: コンソールアプリ - しばっち
2024/10/13 (Sun) 07:49:50
C/C++ライブラリーによるコンソールアプリはcsvファイルからwavファイルを生成します。
https://github.com/audionamix/wave
コマンドプロンプトから
csvtowav sample.csv sample.wav
のように打ち込んでください。
csvtowav.exeはwin32版です。csvtowav64.exeはwin64版になります。
csvファイルのPCMデータ値は-1~1の正規値を入力してください。
この範囲を超えるとクリッピングノイズが発生します。
このプログラムでは精度がfloat型ですが精度的に問題はないかと思います。(ライブラリーがdouble型に対応していない為)
マルチチャンネル入力可能ですが拡張フォーマットには対応していないようです。
VC++2022でコンパイルしました。
下記からダウンロードしてください。(wave.zip)
-------------------------------------------------------------------------------
csvtowav.cpp
#include "wave/file.h"
#include <iostream>
#include <vector>
#include <fstream>
#include <string>
#include <sstream>
#include <iomanip>
using namespace std;
using namespace wave;
float range(float x)
{
if (x<-1.0) x=-1.0;
if (x>1.0) x=1.0;
return x;
}
int main(int argc,char **argv) {
char *wavname,*csvname;
int num,i,samplingfreq,samplebit,channel;
string buf;
File write_file;
if (argc!=3) return 1;
csvname=argv[1];
wavname=argv[2];
ifstream ifs(csvname,ios::in);
if (!ifs) return 1;
ifs >> samplingfreq; // サンプリング周波数
ifs >> samplebit; // サンプルビット
ifs >> channel; // チャンネル数
ifs >> num; // データ数
vector<float> content; //ここがfloat型
string value;
for(i=0; i<num; i++) {
getline(ifs,buf);
stringstream ss(buf);
while(getline(ss,value,',')) content.push_back(stof(value));
}
Error err=write_file.Open(wavname, OpenMode::kOut);
if(err) return 1;
write_file.set_sample_rate(samplingfreq);
write_file.set_bits_per_sample(samplebit);
write_file.set_channel_number(channel);
err=write_file.Write(content); //ここがdouble型未対応
if(err) return 1;
return 0;
}
Re: コンソールアプリ - しばっち
2024/10/13 (Sun) 07:51:01
C/C++ライブラリーによるコンソールアプリはcsvファイルからwavファイルを書き出します。
https://github.com/DIYFXWorld/Other
ヘッダーライブラリーです。ヘッダーファイルをインクルードするだけで使えます。
上記URLからダウンロードしてVC++2022で下記cppソースからコンパイルできます。
コマンドプロンプトから
csvtowave sample.csv sample.wav
のように打ち込んでください。
csvtowave.exeはwin32版です。csvtowave64.exeはwin64版になります。
モノラルかステレオでサンプルビット8bit,16bitのみ対応しています。
VC++2022でコンパイルしました。
-------------------------------------------------------------------------------
csvtowave.cpp
#include "wave.hpp"
#include <fstream>
using namespace std;
int main(int argc,char **argv)
{
int i,samplingfreq,samplebit,channel,num;
char *csvname,*wavname,comma;
if (argc!=3) return 1;
csvname=argv[1];
wavname=argv[2];
ifstream csv(csvname,ios::in);
if (!csv) return 1;
csv >> samplingfreq;
csv >> samplebit;
csv >> channel;
csv >> num;
if (channel>2) return 2;
wave <double> src1(samplingfreq,num);
wave <double> src2(samplingfreq,num,2);
for(i=0; i<num; i++)
{
switch(channel)
{
case 1:
csv >> src1[i];
break;
case 2:
csv >> src2.L[i] >> comma >> src2.R[i];
}
}
switch (samplebit)
{
case 8:
if (channel==1) save(wavname, src1,8);
else save(wavname,src2,8);
break;
case 16:
if (channel==1) save(wavname, src1);
else save(wavname,src2);
}
return 0;
}
Re: コンソールアプリ - しばっち
2024/10/13 (Sun) 07:52:03
C/C++ライブラリーによるコンソールアプリでcsvファイルからwavファイルを書き出します。
https://github.com/Numerix-DSP/wav_file
ヘッダーライブラリーです。ヘッダーファイルをインクルードするだけで使えます。
上記URLからダウンロードしてVC++2022で下記cppソースからコンパイルできます。
コマンドプロンプトから
csvwav sample.csv sample.wav
のように打ち込んでください。
csvwav.exeはwin32版です。csvwav64.exeはwin64版になります。
マルチチャンネル入力可能ですが拡張フォーマットには対応していないようです。
VC++2022でコンパイルしました。
-------------------------------------------------------------------------------
csvwav.c
#include <stdio.h>
#include <stdlib.h>
#include "wav_file.h"
#include <math.h>
int main(int argc,char **argv)
{
FILE *fpwav,*fpcsv;
int samplingfreq,channel,samplebit,num;
char *wavname,*csvname;
double *dat,pcm[8];
WAV_FILE_INFO wavinfo;
if (argc=!3) return 1;
csvname=argv[1];
wavname=argv[2];
if ((fpcsv=fopen(csvname,"r"))==NULL) return 1;
fscanf(fpcsv,"%d",&samplingfreq);
fscanf(fpcsv,"%d",&samplebit);
fscanf(fpcsv,"%d",&channel);
fscanf(fpcsv,"%d",&num);
wavinfo.NumberOfSamples=num*channel;
dat=(double *)malloc(sizeof(double)*num*channel);
if (dat==NULL) {
fclose(fpcsv);
return 1;
}
wavinfo.NumberOfChannels=channel;
wavinfo.SampleRate=samplingfreq;
wavinfo.WordLength=samplebit;
for(int i=0; i<num; i++)
{
switch (channel) {
case 1:
{
fscanf(fpcsv,"%lf",&pcm[0]);
dat[i*channel]=pcm[0]*pow(2.0,samplebit-1);
break;
}
case 2:
{
fscanf(fpcsv,"%lf,%lf",&pcm[0],&pcm[1]);
dat[i*channel]=pcm[0]*pow(2.0,samplebit-1);
dat[i*channel+1]=pcm[1]*pow(2.0,samplebit-1);
break;
}
case 3:
{
fscanf(fpcsv,"%lf,%lf,%lf",&pcm[0],&pcm[1],&pcm[2]);
dat[i*channel]=pcm[0]*pow(2.0,samplebit-1);
dat[i*channel+1]=pcm[1]*pow(2.0,samplebit-1);
dat[i*channel+2]=pcm[2]*pow(2.0,samplebit-1);
break;
}
case 4:
{
fscanf(fpcsv,"%lf,%lf,%lf,%lf",&pcm[0],&pcm[1],&pcm[2],&pcm[3]);
dat[i*channel]=pcm[0]*pow(2.0,samplebit-1);
dat[i*channel+1]=pcm[1]*pow(2.0,samplebit-1);
dat[i*channel+2]=pcm[2]*pow(2.0,samplebit-1);
dat[i*channel+3]=pcm[3]*pow(2.0,samplebit-1);
break;
}
case 5:
{
fscanf(fpcsv,"%lf,%lf,%lf,%lf,%lf",&pcm[0],&pcm[1],&pcm[2],&pcm[3],&pcm[4]);
dat[i*channel]=pcm[0]*pow(2.0,samplebit-1);
dat[i*channel+1]=pcm[1]*pow(2.0,samplebit-1);
dat[i*channel+2]=pcm[2]*pow(2.0,samplebit-1);
dat[i*channel+3]=pcm[3]*pow(2.0,samplebit-1);
dat[i*channel+4]=pcm[4]*pow(2.0,samplebit-1);
break;
}
case 6:
{
fscanf(fpcsv,"%lf,%lf,%lf,%lf,%lf,%lf",&pcm[0],&pcm[1],&pcm[2],&pcm[3],&pcm[4],&pcm[5]);
dat[i*channel]=pcm[0]*pow(2.0,samplebit-1);
dat[i*channel+1]=pcm[1]*pow(2.0,samplebit-1);
dat[i*channel+2]=pcm[2]*pow(2.0,samplebit-1);
dat[i*channel+3]=pcm[3]*pow(2.0,samplebit-1);
dat[i*channel+4]=pcm[4]*pow(2.0,samplebit-1);
dat[i*channel+5]=pcm[5]*pow(2.0,samplebit-1);
break;
}
case 7:
{
fscanf(fpcsv,"%lf,%lf,%lf,%lf,%lf,%lf,%lf",&pcm[0],&pcm[1],&pcm[2],&pcm[3],&pcm[4],&pcm[5],&pcm[6]);
dat[i*channel]=pcm[0]*pow(2.0,samplebit-1);
dat[i*channel+1]=pcm[1]*pow(2.0,samplebit-1);
dat[i*channel+2]=pcm[2]*pow(2.0,samplebit-1);
dat[i*channel+3]=pcm[3]*pow(2.0,samplebit-1);
dat[i*channel+4]=pcm[4]*pow(2.0,samplebit-1);
dat[i*channel+5]=pcm[5]*pow(2.0,samplebit-1);
dat[i*channel+6]=pcm[6]*pow(2.0,samplebit-1);
break;
}
case 8:
{
fscanf(fpcsv,"%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf",&pcm[0],&pcm[1],&pcm[2],&pcm[3],&pcm[4],&pcm[5],&pcm[6],&pcm[7]);
dat[i*channel]=pcm[0]*pow(2.0,samplebit-1);
dat[i*channel+1]=pcm[1]*pow(2.0,samplebit-1);
dat[i*channel+2]=pcm[2]*pow(2.0,samplebit-1);
dat[i*channel+3]=pcm[3]*pow(2.0,samplebit-1);
dat[i*channel+4]=pcm[4]*pow(2.0,samplebit-1);
dat[i*channel+5]=pcm[5]*pow(2.0,samplebit-1);
dat[i*channel+6]=pcm[6]*pow(2.0,samplebit-1);
dat[i*channel+7]=pcm[7]*pow(2.0,samplebit-1);
break;
}
default :
{
fclose(fpcsv);
free(dat);
return 3;
}
}
}
if((fpwav=fopen(wavname,"wb"))==NULL) return 1;
wav_write_header(fpwav,wavinfo);
wav_write_data (dat, fpwav, wavinfo, num*channel);
fclose(fpwav);
fclose(fpcsv);
free(dat);
return 0;
}
Re: コンソールアプリ - しばっち
2024/10/13 (Sun) 07:53:39
csvファイル読み込み
マルチチャンネル対応のため一部仕様を変更しています。
配列不足の場合はエラーで実行が止まります。
EXTERNAL SUB READCSV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT(,),ERR)
DIM S$(CHANNEL)
LET ERR=0
WHEN EXCEPTION IN
OPEN #1:NAME F$
ASK #1: FILESIZE SIZE
USE
LET ERR=3
CLOSE #1
EXIT SUB
END WHEN
IF SIZE=0 THEN
LET ERR=2
CLOSE #1
EXIT SUB
END IF
INPUT #1:SAMPLINGFREQ
INPUT #1:SAMPLEBIT
INPUT #1:CHANNEL
INPUT #1:NUM
LET A=INT(NUM/100)
PRINT "読み込み中"
FOR K=1 TO NUM
IF MOD(K,INT(NUM/A))=0 AND INT(K/A)<>R THEN
LET R=INT(K/A)
PRINT R;"%"
END IF
SELECT CASE CHANNEL
CASE 1
INPUT #1:DAT(1,K) ! モノラル
CASE 2
INPUT #1:DAT(1,K),DAT(2,K) ! フロント左、フロント右(ステレオ)
CASE 3
INPUT #1:DAT(1,K),DAT(2,K),DAT(3,K) ! フロント左、フロント右、フロント中央
CASE 4
INPUT #1:DAT(1,K),DAT(2,K),DAT(3,K),DAT(4,K) ! フロント左、フロント右、フロント中央、リア中央(サラウンド)
CASE 5
INPUT #1:DAT(1,K),DAT(2,K),DAT(3,K),DAT(4,K),DAT(5,K) ! フロント左、フロント右、フロント中央、リア左、リア右
CASE 6
INPUT #1:DAT(1,K),DAT(2,K),DAT(3,K),DAT(4,K),DAT(5,K),DAT(6,K) ! フロント左、フロント右、フロント中央、低周波用、サイド左、サイド右(5.1チャンネル)
CASE 7
INPUT #1:DAT(1,K),DAT(2,K),DAT(3,K),DAT(4,K),DAT(5,K),DAT(6,K),DAT(7,K) ! フロント左、フロント右、フロント中央、低周波用、リア中央、サイド左、サイド右
CASE 8
INPUT #1:DAT(1,K),DAT(2,K),DAT(3,K),DAT(4,K),DAT(5,K),DAT(6,K),DAT(7,K),DAT(8,K) ! フロント左、フロント右、フロント中央、低周波用、リア左、リア右、サイド左、サイド右(7.1チャンネル)
CASE ELSE
LINE INPUT #1:A$
CALL TOKUN(A$,S$,KK)
FOR CH=1 TO KK
LET DAT(CH,I)=VAL(S$(CH))
NEXT CH
END SELECT
NEXT K
CLOSE #1
END SUB
EXTERNAL SUB TOKUN(A$,X$(),K) !'トークン取り出し
LET B$=A$
LET K=0
DO
LET N=POS(B$,",") !'区切り文字 ","
IF N>0 THEN
LET K=K+1
LET X$(K)=FRONTSTRING$(B$,",")
LET B$=BEHINDSTRING$(B$,",")
END IF
LOOP UNTIL N=0
LET K=K+1
IF RIGHT$(B$,1)="," THEN
LET X$(K)=LEFT$(B$,LEN(B$)-1)
ELSE
LET X$(K)=B$
END IF
END SUB
EXTERNAL FUNCTION FRONTSTRING$(A$,B$) !'前方取り出し
LET N=POS(A$,B$,1)
IF N=0 THEN
LET FRONTSTRING$=A$
ELSE
LET FRONTSTRING$=A$(1:N-1)
END IF
END FUNCTION
EXTERNAL FUNCTION BEHINDSTRING$(A$,B$) !'後方取り出し
LET N=POS(A$,B$,1)
IF N=0 THEN
LET BEHINDSTRING$=A$
ELSE
LET BEHINDSTRING$=A$(N+LEN(B$):LEN(A$))
END IF
END FUNCTION
--------------------------------------------------------------------------------
次のようにすると高速に読み込みできます。
EXTERNAL SUB READCSV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT(,),ERR)
LET ERR=0
IF F$="" THEN
LET ERR=1
EXIT SUB
END IF
OPEN #1:NAME F$,RECTYPE CSV
READ #1:SAMPLINGFREQ
READ #1:SAMPLEBIT
READ #1:CHANNEL
READ #1:NUM
REDIM DAT(CHANNEL,NUM)
MAT READ #1:DAT
CLOSE #1
END SUB
--------------------------------------------------------------------------------
マルチチャンネルwavファイル書き出し
マルチチャンネル対応のため一部仕様を変更しています。
EXTERNAL SUB WRITEWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,OUT(,))
OPTION CHARACTER BYTE
IF POS(LCASE$(F$),".wav")=0 THEN LET F$=F$&".wav"
OPEN #1:NAME F$
ERASE #1
SELECT CASE SAMPLEBIT
CASE 8,16,24,32
CASE ELSE
LET SAMPLEBIT=16
END SELECT
IF NUM=0 THEN LET NUM=UBOUND(OUT,2)
LET HEADERSIZE=16
LET WAVETYPE=1
LET PLAYTIME=NUM/SAMPLINGFREQ
LET SAMPLESIZE=SAMPLEBIT/8*CHANNEL
LET DATARATE = SAMPLESIZE * SAMPLINGFREQ
LET PCMSIZE=INT(DATARATE*PLAYTIME)
LET WAVEFILESIZE=PCMSIZE+36
PRINT #1:"RIFF";
PRINT #1:DWORD$(WAVEFILESIZE);
PRINT #1:"WAVE";
IF EXTENSION=1 AND CHANNEL>2 THEN ! 拡張フォーマット
LET CHUNKSIZE=40
LET BLOCKSIZE=SAMPLEBIT/8*CHANNEL
LET COMPRESS=SAMPLINGFREQ*BLOCKSIZE
LET BITPERSAMPLE=SAMPLEBIT
LET CHANNELMASK=2^CHANNEL-1
LET CBSIZE=22
PRINT #1:"fmt ";
PRINT #1:DWORD$(CHUNKSIZE);
PRINT #1:HEX$("FFFE");
PRINT #1:WORD$(CHANNEL);
PRINT #1:DWORD$(SAMPLINGFREQ);
PRINT #1:DWORD$(COMPRESS);
PRINT #1:WORD$(BLOCKSIZE);
PRINT #1:WORD$(BITPERSAMPLE);
PRINT #1:WORD$(CBSIZE);
PRINT #1:WORD$(SAMPLEBIT);
PRINT #1:DWORD$(CHANNELMASK);
PRINT #1:HEX$("00000001");
PRINT #1:HEX$("0000");
PRINT #1:HEX$("0010");
PRINT #1:HEX$("AA000080");
PRINT #1:HEX$("719B3800");
ELSE
PRINT #1:"fmt ";
PRINT #1:DWORD$(HEADERSIZE);
PRINT #1:WORD$(WAVETYPE);
PRINT #1:WORD$(CHANNEL);
PRINT #1:DWORD$(SAMPLINGFREQ);
PRINT #1:DWORD$(DATARATE);
PRINT #1:WORD$(SAMPLESIZE);
PRINT #1:WORD$(SAMPLEBIT);
END IF
PRINT #1:"data";
PRINT #1:DWORD$(PCMSIZE);
LET A=INT(NUM/100)
PRINT "書き出し中"
FOR K=1 TO NUM
IF MOD(K,INT(NUM/A))=0 AND INT(K/A)<>R THEN
LET R=INT(K/A)
PRINT R;"%"
END IF
FOR CH=1 TO CHANNEL
LET OUT(CH,K)=MIN(1,MAX(OUT(CH,K),-1))
SELECT CASE SAMPLEBIT
CASE 8
PRINT #1:CHR$(OUT(CH,K)*127+128);
CASE 16
PRINT #1:WORD$(OUT(CH,K)*2^15);
CASE 24
PRINT #1:WORD24$(OUT(CH,K)*2^23);
CASE 32
PRINT #1:DWORD$(OUT(CH,K)*2^31);
END SELECT
NEXT CH
NEXT K
CLOSE #1
END SUB
EXTERNAL FUNCTION WORD24$(X)
OPTION CHARACTER BYTE
LET A$=DWORD$(X)
LET WORD24$=A$(1:3)
END FUNCTION
EXTERNAL FUNCTION HEX$(X$)
OPTION CHARACTER BYTE
FOR I=1 TO LEN(X$) STEP 2
LET S$=CHR$(BVAL(X$(I:I+1),16))&S$
NEXT I
LET HEX$=S$
END FUNCTION
-------------------------------------------------------------
使用例
マルチチャンネルcsvファイルからマルチチャンネルwavファイルを書き出します。
こちらはCSV2WAV.EXE等の代替プログラムになります。
LET NUM=44100*200
LET CH=6
DIM DAT(CH,NUM)
FILE GETOPENNAME F$,"読み込み CSVファイル|*.csv"
IF F$="" THEN STOP
CALL READCSV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT,ERR)
IF ERR>0 THEN STOP
FILE GETSAVENAME G$,"保存 WAVファイル|*.wav"
IF G$="" THEN STOP
CALL WRITEWAV(G$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT)
END
以下略
wavファイル読み込みルーチン - しばっち
2024/10/13 (Sun) 07:09:48
wavファイル読み込みルーチン
サブルーチンREADWAVはプログラム簡略化のためwavファイルを一旦全て配列に読み込みます。
wavファイルを読み込みながら処理していけば曲長にかかわらず処理できますが、プログラムが煩雑になるため
一旦全てのPCMデータを配列に取り込むようにしています。そのためwav読み込み部とデータ処理部(加工部)とwav書き込み部に分けることができます。
※全てのwavファイルが読み込めるわけではありません。(無圧縮リニアPCM形式リトルエンディアン符号有り整数)
※読み込みには多少時間がかかります。
CHARACTER INPUT # の読み込みが遅いのが原因です。
できればA$=INPUT$(#1,SIZE)のように読み込みサイズ指定(バイト数)ができるといいです。欲を言えばシークもできたらもっといい(SEEK #1,POS)
書式をA$=INPUT$(#1,SIZE,SEEK)としてもいい。
F$に読み込むwavファイル名と十分な長さの配列を与えると
戻り値としてNUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,配列LIN,RINとERRを返します。
NUMは読み込んだサンプル数です。再生時間(秒)はNUM/SAMPLINGFREQで求められます。
0~NUM-1ではなく、1~NUMが範囲となります。OPTION BASE 0は不要です。
チャンネル数に関係なく1~NUMです。
CHANNELはチャンネル数です。
CHANNEL=1の時は配列LINにのみ代入されます。
CHANNEL=2の時は左チャネルが配列LINに右チャンネルが配列RINに代入されます。
3チャンネル以上は無視します。
PCMデータは-1~1に正規化されています。
SAMPLINGFREQは読み込んだサンプリング周波数です。
ERR>0の時は読み込みに失敗しています。
バッファーサイズが足りない時はエラーで実行が止まります。
読み込みに十分な配列サイズを与えてください。但し、あまりに大きくし過ぎるとメモリー不足エラーになります。
想定では2^24(16777216)までとしています。(※Windows版 32bit版十進BASICでの話です。 64bit版十進BASICではこの限りではありません)
目安はサンプリング周波数(44100か48000辺り)に秒数(演奏時間)を掛けた値です。
ERRはエラー箇所を特定するエラーコードです。
サンプリング周波数44100Hzで曲長3分なら44100*180=7938000 ステレオならば更に倍のメモリー(配列変数を2つ)を必要とします。
更にデータ処理(加工処理)して書き出すのならば同サイズの配列(作業用配列)が更に必要です。
オンメモリーで作業するため、32ビット版ではあまり大きなファイル(曲長4~5分程度?)は読み込めないかもしれません。
複数の曲を繋げたメドレー等は32ビット版での読み込みは厳しいかもしれません。
その場合は64ビット版十進BASIC(Lazarus版)又はコンパイル(64bit)して使用してください。(※搭載メモリー8GB できれば16GB以上を想定)
https://decimalbasic.web.fc2.com/BASICGenJa.htm
https://decimalbasic.web.fc2.com/BASICAccJa.htm
https://decimalbasic.web.fc2.com/BASICAcc2Ja.htm
このREADWAVルーチンで読み込んだPCMデータはWRITEWAVルーチンで書き出しできます。
2進モードで実行してください。
EXTERNAL SUB READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN(),RIN(),ERR)
OPTION CHARACTER BYTE
DIM A$(40)
LET ERR=0
WHEN EXCEPTION IN
OPEN #1:NAME F$
ASK #1: FILESIZE SIZE
USE
LET ERR=4
CLOSE #1
EXIT SUB
END WHEN
IF SIZE=0 THEN
LET ERR=3
CLOSE #1
EXIT SUB
END IF
FOR I=1 TO 12
CHARACTER INPUT #1:A$(I)
NEXT I
IF A$(1)&A$(2)&A$(3)&A$(4)<>"RIFF" THEN
LET ERR=2
!PRINT "WAVファイルではありません"
CLOSE #1
EXIT SUB
END IF
LET WAVEFILESIZE=INT32(A$(5)&A$(6)&A$(7)&A$(8))
IF A$(9)&A$(10)&A$(11)&A$(12)<>"WAVE" THEN
LET ERR=2
!PRINT "WAVファイルではありません"
CLOSE #1
EXIT SUB
END IF
DO
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
SELECT CASE A$(1)&A$(2)&A$(3)&A$(4)
CASE "fmt "
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET HEADERSIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
FOR I=1 TO HEADERSIZE
CHARACTER INPUT #1:A$(I)
NEXT I
IF HEADERSIZE=16 OR HEADERSIZE=18 THEN ! 標準フォーマット
LET WAVETYPE=INT16(A$(1)&A$(2))
IF WAVETYPE<>1 THEN
LET ERR=1
! PRINT "対応していません"
CLOSE #1
EXIT SUB
END IF
LET CHANNEL=INT16(A$(3)&A$(4))
LET SAMPLINGFREQ=INT32(A$(5)&A$(6)&A$(7)&A$(8))
LET DATARATE=INT32(A$(9)&A$(10)&A$(11)&A$(12))
LET SAMPLESIZE=INT16(A$(13)&A$(14))
LET SAMPLEBIT=INT16(A$(15)&A$(16))
IF HEADERSIZE=18 THEN LET CBSIZE=INT16(A$(17)&A$(18))
ELSEIF HEADERSIZE=40 THEN ! 拡張フォーマット
LET TMP=INT16(A$(1)&A$(2))
LET CHANNEL=INT16(A$(3)&A$(4))
LET SAMPLINGFREQ=INT32(A$(5)&A$(6)&A$(7)&A$(8))
LET COMPRESS=INT32(A$(9)&A$(10)&A$(11)&A$(12))
LET SAMPLESIZE=INT16(A$(13)&A$(14))
LET SAMPLEBIT=INT16(A$(15)&A$(16))
LET CBSIZE=INT16(A$(17)&A$(18))
LET BITPERSAMPLE=INT16(A$(19)&A$(20))
LET CHANNELMASK=INT32(A$(21)&A$(22)&A$(23)&A$(24))
ELSE
LET ERR=2
CLOSE #1
EXIT SUB
END IF
CASE "data"
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET PCMSIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
!LET SECOND=PCMSIZE/DATARATE
!' LET NUM=INT(SAMPLINGFREQ*SECOND)
LET NUM=PCMSIZE/SAMPLESIZE
EXIT DO
CASE "fact"
FOR I=1 TO 8
CHARACTER INPUT #1:A$(I)
NEXT I
!' LET SIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
!' LET SAMPLE=INT32(A$(5)&A$(6)&A$(7)&A$(8))
CASE "LIST"
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET SIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
FOR I=1 TO SIZE
CHARACTER INPUT #1:DMY$
NEXT I
CASE "JUNK"
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET SIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
FOR I=1 TO SIZE
CHARACTER INPUT #1:DMY$
NEXT I
CASE ELSE
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET SIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
FOR I=1 TO SIZE
CHARACTER INPUT #1:DMY$
NEXT I
END SELECT
LOOP
!!REDIM LIN(NUM)
!!REDIM RIN(NUM)
LET B$=REPEAT$(CHR$(0),8)
LET A=INT(NUM/100)
PRINT "読み込み中"
FOR K=1 TO NUM
IF MOD(K,INT(NUM/A))=0 AND INT(K/A)<>R THEN
LET R=INT(K/A)
PRINT R;"%" ! カウンター表示
END IF
FOR CH=1 TO CHANNEL
FOR J=1 TO SAMPLEBIT/8
CHARACTER INPUT #1:B$(J:J)
NEXT J
SELECT CASE SAMPLEBIT
CASE 8
LET DAT=(ORD(B$(1:1))-128)/2^7
CASE 16
LET DAT=INT16(B$(1:2))/2^15
CASE 24
LET DAT=INT24(B$(1:3))/2^23
CASE 32
LET DAT=INT32(B$(1:4))/2^31
END SELECT
SELECT CASE CH
CASE 1
LET LIN(K)=DAT
CASE 2
LET RIN(K)=DAT
CASE ELSE
END SELECT
NEXT CH
NEXT K
CLOSE #1
END SUB
EXTERNAL FUNCTION INT16(A$)
OPTION CHARACTER BYTE
DECLARE NUMERIC A
LET A$=LEFT$(A$,2)
LET A=ORD(A$(1:1))+ORD(A$(2:2))*256
IF A>2^15-1 THEN LET A=A-2^16
LET INT16=A
END FUNCTION
EXTERNAL FUNCTION INT24(A$)
OPTION CHARACTER BYTE
DECLARE NUMERIC A
LET A$=LEFT$(A$,3)
LET A=ORD(A$(1:1))+ORD(A$(2:2))*256+ORD(A$(3:3))*65536
IF A>2^23-1 THEN LET A=A-2^24
LET INT24=A
END FUNCTION
EXTERNAL FUNCTION INT32(A$)
OPTION CHARACTER BYTE
DECLARE NUMERIC A
LET A$=LEFT$(A$,4)
LET A=ORD(A$(1:1))+ORD(A$(2:2))*256+ORD(A$(3:3))*256^2+ORD(A$(4:4))*256^3
IF A>=2^31-1 THEN LET A=A-2^32
LET INT32=A
END FUNCTION
-------------------------------------------------------------------------------------------------
高速版
WINDOWS APIを使用して一度にファイルを読み込みます。
但し、メモリーが余分に必要です。
EXTERNAL SUB READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN(),RIN(),ERR)
OPTION CHARACTER BYTE
LET ERR=0
LET GETDATA$=FILEREAD$(F$)
IF GETDATA$="" THEN
LET ERR=2
EXIT SUB
END IF
IF GETDATA$(1:4)<>"RIFF" THEN
LET ERR=1
!PRINT "WAVファイルではありません"
EXIT SUB
END IF
LET WAVEFILESIZE=INT32(GETDATA$(5:8))
IF GETDATA$(9:12)<>"WAVE" THEN
LET ERR=1
!PRINT "WAVファイルではありません"
EXIT SUB
END IF
LET SEEK=12
DO
LET SEEK=SEEK+4
SELECT CASE GETDATA$(SEEK-3:SEEK)
CASE "fmt "
LET HEADERSIZE=INT32(GETDATA$(SEEK+1:SEEK+4))
LET SEEK=SEEK+4
LET WAVETYPE=INT16(GETDATA$(SEEK+1:SEEK+2))
IF WAVETYPE<>1 THEN
LET ERR=1
!PRINT "対応していません"
EXIT SUB
END IF
LET CHANNEL=INT16(GETDATA$(SEEK+3:SEEK+4))
LET SAMPLINGFREQ=INT32(GETDATA$(SEEK+5:SEEK+8))
LET DATARATE=INT32(GETDATA$(SEEK+9:SEEK+12))
LET SAMPLESIZE=INT16(GETDATA$(SEEK+13:SEEK+14))
LET SAMPLEBIT=INT16(GETDATA$(SEEK+15:SEEK+16))
LET SEEK=SEEK+HEADERSIZE
CASE "data"
LET PCMSIZE=INT32(GETDATA$(SEEK+1:SEEK+4))
LET SECOND=PCMSIZE/DATARATE
LET NUM=PCMSIZE/SAMPLESIZE
LET SEEK=SEEK+4
EXIT DO
CASE "fact"
!'LET SIZE=INT32(GETDATA$(SEEK+1:SEEK+4)
!'LET PCMSIZE=INT32(GETDATA$(SEEK+5:SEEK+7))
LET SEEK=SEEK+8
CASE "LIST"
LET LISTSIZE=INT32(GETDATA$(SEEK+1:SEEK+4))
LET SEEK=SEEK+4+LISTSIZE
CASE ELSE
! PRINT "対応していません"
LET ERR=1
EXIT SUB
END SELECT
LOOP
!REDIM LIN(NUM)
!REDIM RIN(NUM)
FOR K=1 TO NUM
FOR CH=1 TO CHANNEL
SELECT CASE SAMPLEBIT
CASE 8
LET B$=GETDATA$(SEEK:SEEK)
LET SEEK=SEEK+1
LET DAT=(ORD(B$)-128)/2^7
CASE 16
LET B$=GETDATA$(SEEK:SEEK+1)
LET SEEK=SEEK+2
LET DAT=INT16(B$)/2^15
CASE 24
LET B$=GETDATA$(SEEK:SEEK+2)
LET SEEK=SEEK+3
LET DAT=INT24(B$)/2^23
CASE 32
LET B$=GETDATA$(SEEK:SEEK+4)
LET SEEK=SEEK+4
LET DAT=INT32(B$)/2^31
END SELECT
SELECT CASE CH
CASE 1
LET LIN(K)=DAT
CASE 2
LET RIN(K)=DAT
CASE ELSE
END SELECT
NEXT CH
NEXT K
END SUB
EXTERNAL FUNCTION FILEREAD$(NAME$) ! ファイル読み込み
OPTION CHARACTER BYTE
OPEN #1:NAME NAME$
ASK #1: FILESIZE NUM
CLOSE #1
IF NUM=0 THEN
LET FILEREAD$=""
EXIT FUNCTION
ELSE
LET GENERIC_READ=BVAL("80000000",16)
LET OPEN_EXISTING=3
LET FILE_ATTRIBUTE_NORMAL=BVAL("80",16)
LET W$="0000" ! 4バイト確保
LET HFILE=CREATEFILE(NAME$,GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0)
IF HFILE<>-1 THEN
LET S$=REPEAT$(CHR$(0),NUM) ! メモリー確保
CALL READFILE(HFILE,S$,NUM,W$,0)
CALL CLOSEHANDLE(HFILE)
ELSE
LET FILEREAD$=""
EXIT FUNCTION
END IF
LET FILEREAD$=S$(1:NUM)
END IF
FUNCTION CREATEFILE(NAME$, ACC ,SHARE, SEC, CREATE, ATTRIB, HANDLE)
ASSIGN "kernel32.dll","CreateFileA"
END FUNCTION
SUB READFILE(HANDLE, S$, L, W$, OV )
ASSIGN "kernel32.dll","ReadFile"
END SUB
SUB CLOSEHANDLE(HANDLE)
ASSIGN "kernel32.dll","CloseHandle"
END SUB
END FUNCTION
!EXTERNAL FUNCTION FILEREAD$(NAME$) ! ファイル読み込み
!OPTION CHARACTER BYTE
!OPEN #1:NAME NAME$,ACCESS INPUT
!SET #1: ENDOFLINE CHR$(13)
!ASK #1: FILESIZE S9
!LET CX=S9 ! cx=bytes size
!LET DB$=""
!DO
! LET W9=LEN(W9$)-CX
! IF 0=<W9 THEN
! LET DB$=DB$ &LEFT$(W9$,CX)
! LET S99=S99+CX
! LET W9$=RIGHT$(W9$,W9)
! EXIT DO
! END IF
! LET DB$=DB$ &W9$
! LET S99=S99+LEN(W9$)
! LET W9$=""
! LET CX=-W9
! LINE INPUT #1,IF MISSING THEN EXIT DO :W9$
! IF S99+LEN(W9$)<S9 THEN LET W9$=W9$ &CHR$(13)
!LOOP
!CLOSE #1
!LET FILEREAD$=DB$(1:S9)
!END FUNCTION
以下略
Re: wavファイル読み込みルーチン - しばっち
2024/10/13 (Sun) 07:11:30
サンプル画像のようにカラーマップを定義すると数値の代わりにその色で表すことができます。
左側(青)は低値を表し、右側(赤)は高値を表しています。
https://jp.mathworks.com/help/matlab/ref/jet.html
https://qiita.com/shimacpyon/items/9902b685a7a95e824a58
https://pygraph.helve-blog.com/matplotlib-conf/colormap
CALL JETCOLORMAP
SET WINDOW 0,255,0,255
FOR I=0 TO 255
SET AREA COLOR I
PLOT AREA:I,0;I+1,0;I+1,255;I,255
NEXT I
END
EXTERNAL SUB JETCOLORMAP
FOR I=0 TO 255
READ R,G,B
SET COLOR MIX(I) R,G,B
NEXT I
DATA 0 , 0 , 1
DATA 0 , 1.56862745098039E-2 , 1
DATA 0 , 3.13725490196078E-2 , 1
DATA 0 , 4.70588235294118E-2 , 1
DATA 0 , 6.27450980392157E-2 , 1
DATA 0 , 7.84313725490196E-2 , 1
DATA 0 , 9.41176470588235E-2 , 1
DATA 0 , .109803921568627 , 1
DATA 0 , .125490196078431 , 1
DATA 0 , .141176470588235 , 1
DATA 0 , .156862745098039 , 1
DATA 0 , .172549019607843 , 1
DATA 0 , .188235294117647 , 1
DATA 0 , .203921568627451 , 1
DATA 0 , .219607843137255 , 1
DATA 0 , .235294117647059 , 1
DATA 0 , .250980392156863 , 1
DATA 0 , .266666666666667 , 1
DATA 0 , .282352941176471 , 1
DATA 0 , .298039215686275 , 1
DATA 0 , .313725490196078 , 1
DATA 0 , .329411764705882 , 1
DATA 0 , .345098039215686 , 1
DATA 0 , .36078431372549 , 1
DATA 0 , .376470588235294 , 1
DATA 0 , .392156862745098 , 1
DATA 0 , .407843137254902 , 1
DATA 0 , .423529411764706 , 1
DATA 0 , .43921568627451 , 1
DATA 0 , .454901960784314 , 1
DATA 0 , .470588235294118 , 1
DATA 0 , .486274509803922 , 1
DATA 0 , .501960784313725 , 1
DATA 0 , .517647058823529 , 1
DATA 0 , .533333333333333 , 1
DATA 0 , .549019607843137 , 1
DATA 0 , .564705882352941 , 1
DATA 0 , .580392156862745 , 1
DATA 0 , .596078431372549 , 1
DATA 0 , .611764705882353 , 1
DATA 0 , .627450980392157 , 1
DATA 0 , .643137254901961 , 1
DATA 0 , .658823529411765 , 1
DATA 0 , .674509803921569 , 1
DATA 0 , .690196078431373 , 1
DATA 0 , .705882352941177 , 1
DATA 0 , .72156862745098 , 1
DATA 0 , .737254901960784 , 1
DATA 0 , .752941176470588 , 1
DATA 0 , .768627450980392 , 1
DATA 0 , .784313725490196 , 1
DATA 0 , .8 , 1
DATA 0 , .815686274509804 , 1
DATA 0 , .831372549019608 , 1
DATA 0 , .847058823529412 , 1
DATA 0 , .862745098039216 , 1
DATA 0 , .87843137254902 , 1
DATA 0 , .894117647058824 , 1
DATA 0 , .909803921568627 , 1
DATA 0 , .925490196078431 , 1
DATA 0 , .941176470588235 , 1
DATA 0 , .956862745098039 , 1
DATA 0 , .972549019607843 , 1
DATA 0 , .988235294117647 , 1
DATA 0 , 1 , .996078431372549
DATA 0 , 1 , .980392156862745
DATA 0 , 1 , .964705882352941
DATA 0 , 1 , .949019607843137
DATA 0 , 1 , .933333333333333
DATA 0 , 1 , .917647058823529
DATA 0 , 1 , .901960784313725
DATA 0 , 1 , .886274509803922
DATA 0 , 1 , .870588235294118
DATA 0 , 1 , .854901960784314
DATA 0 , 1 , .83921568627451
DATA 0 , 1 , .823529411764706
DATA 0 , 1 , .807843137254902
DATA 0 , 1 , .792156862745098
DATA 0 , 1 , .776470588235294
DATA 0 , 1 , .76078431372549
DATA 0 , 1 , .745098039215686
DATA 0 , 1 , .729411764705882
DATA 0 , 1 , .713725490196078
DATA 0 , 1 , .698039215686274
DATA 0 , 1 , .682352941176471
DATA 0 , 1 , .666666666666667
DATA 0 , 1 , .650980392156863
DATA 0 , 1 , .635294117647059
DATA 0 , 1 , .619607843137255
DATA 0 , 1 , .603921568627451
DATA 0 , 1 , .588235294117647
DATA 0 , 1 , .572549019607843
DATA 0 , 1 , .556862745098039
DATA 0 , 1 , .541176470588235
DATA 0 , 1 , .525490196078431
DATA 0 , 1 , .509803921568627
DATA 0 , 1 , .494117647058824
DATA 0 , 1 , .47843137254902
DATA 0 , 1 , .462745098039216
DATA 0 , 1 , .447058823529412
DATA 0 , 1 , .431372549019608
DATA 0 , 1 , .415686274509804
DATA 0 , 1 , .4
DATA 0 , 1 , .384313725490196
DATA 0 , 1 , .368627450980392
DATA 0 , 1 , .352941176470588
DATA 0 , 1 , .337254901960784
DATA 0 , 1 , .32156862745098
DATA 0 , 1 , .305882352941176
DATA 0 , 1 , .290196078431373
DATA 0 , 1 , .274509803921569
DATA 0 , 1 , .258823529411765
DATA 0 , 1 , .243137254901961
DATA 0 , 1 , .227450980392157
DATA 0 , 1 , .211764705882353
DATA 0 , 1 , .196078431372549
DATA 0 , 1 , .180392156862745
DATA 0 , 1 , .164705882352941
DATA 0 , 1 , .149019607843137
DATA 0 , 1 , .133333333333333
DATA 0 , 1 , .117647058823529
DATA 0 , 1 , .101960784313726
DATA 0 , 1 , 8.62745098039215E-2
DATA 0 , 1 , 7.05882352941176E-2
DATA 0 , 1 , 5.49019607843138E-2
DATA 0 , 1 , 3.92156862745099E-2
DATA 0 , 1 , 2.35294117647058E-2
DATA 0 , 1 , 7.84313725490193E-3
DATA 7.84313725490193E-3 , 1 , 0
DATA 2.35294117647058E-2 , 1 , 0
DATA 3.92156862745097E-2 , 1 , 0
DATA 5.49019607843135E-2 , 1 , 0
DATA 7.05882352941178E-2 , 1 , 0
DATA 8.62745098039217E-2 , 1 , 0
DATA .101960784313726 , 1 , 0
DATA .117647058823529 , 1 , 0
DATA .133333333333333 , 1 , 0
DATA .149019607843137 , 1 , 0
DATA .164705882352941 , 1 , 0
DATA .180392156862745 , 1 , 0
DATA .196078431372549 , 1 , 0
DATA .211764705882353 , 1 , 0
DATA .227450980392157 , 1 , 0
DATA .243137254901961 , 1 , 0
DATA .258823529411765 , 1 , 0
DATA .274509803921569 , 1 , 0
DATA .290196078431372 , 1 , 0
DATA .305882352941176 , 1 , 0
DATA .321568627450981 , 1 , 0
DATA .337254901960784 , 1 , 0
DATA .352941176470588 , 1 , 0
DATA .368627450980392 , 1 , 0
DATA .384313725490196 , 1 , 0
DATA .4 , 1 , 0
DATA .415686274509804 , 1 , 0
DATA .431372549019608 , 1 , 0
DATA .447058823529412 , 1 , 0
DATA .462745098039216 , 1 , 0
DATA .47843137254902 , 1 , 0
DATA .494117647058824 , 1 , 0
DATA .509803921568627 , 1 , 0
DATA .525490196078431 , 1 , 0
DATA .541176470588235 , 1 , 0
DATA .556862745098039 , 1 , 0
DATA .572549019607843 , 1 , 0
DATA .588235294117647 , 1 , 0
DATA .603921568627451 , 1 , 0
DATA .619607843137255 , 1 , 0
DATA .635294117647059 , 1 , 0
DATA .650980392156863 , 1 , 0
DATA .666666666666667 , 1 , 0
DATA .68235294117647 , 1 , 0
DATA .698039215686275 , 1 , 0
DATA .713725490196079 , 1 , 0
DATA .729411764705882 , 1 , 0
DATA .745098039215686 , 1 , 0
DATA .76078431372549 , 1 , 0
DATA .776470588235294 , 1 , 0
DATA .792156862745098 , 1 , 0
DATA .807843137254902 , 1 , 0
DATA .823529411764706 , 1 , 0
DATA .83921568627451 , 1 , 0
DATA .854901960784314 , 1 , 0
DATA .870588235294118 , 1 , 0
DATA .886274509803922 , 1 , 0
DATA .901960784313725 , 1 , 0
DATA .917647058823529 , 1 , 0
DATA .933333333333333 , 1 , 0
DATA .949019607843137 , 1 , 0
DATA .964705882352941 , 1 , 0
DATA .980392156862745 , 1 , 0
DATA .996078431372549 , 1 , 0
DATA 1 , .988235294117647 , 0
DATA 1 , .972549019607843 , 0
DATA 1 , .956862745098039 , 0
DATA 1 , .941176470588236 , 0
DATA 1 , .925490196078431 , 0
DATA 1 , .909803921568627 , 0
DATA 1 , .894117647058823 , 0
DATA 1 , .87843137254902 , 0
DATA 1 , .862745098039216 , 0
DATA 1 , .847058823529412 , 0
DATA 1 , .831372549019608 , 0
DATA 1 , .815686274509804 , 0
DATA 1 , .8 , 0
DATA 1 , .784313725490196 , 0
DATA 1 , .768627450980392 , 0
DATA 1 , .752941176470588 , 0
DATA 1 , .737254901960784 , 0
DATA 1 , .72156862745098 , 0
DATA 1 , .705882352941177 , 0
DATA 1 , .690196078431373 , 0
DATA 1 , .674509803921568 , 0
DATA 1 , .658823529411765 , 0
DATA 1 , .643137254901961 , 0
DATA 1 , .627450980392157 , 0
DATA 1 , .611764705882353 , 0
DATA 1 , .596078431372549 , 0
DATA 1 , .580392156862745 , 0
DATA 1 , .564705882352941 , 0
DATA 1 , .549019607843137 , 0
DATA 1 , .533333333333333 , 0
DATA 1 , .517647058823529 , 0
DATA 1 , .501960784313725 , 0
DATA 1 , .486274509803922 , 0
DATA 1 , .470588235294118 , 0
DATA 1 , .454901960784314 , 0
DATA 1 , .43921568627451 , 0
DATA 1 , .423529411764706 , 0
DATA 1 , .407843137254902 , 0
DATA 1 , .392156862745098 , 0
DATA 1 , .376470588235294 , 0
DATA 1 , .36078431372549 , 0
DATA 1 , .345098039215686 , 0
DATA 1 , .329411764705883 , 0
DATA 1 , .313725490196079 , 0
DATA 1 , .298039215686274 , 0
DATA 1 , .28235294117647 , 0
DATA 1 , .266666666666667 , 0
DATA 1 , .250980392156863 , 0
DATA 1 , .235294117647059 , 0
DATA 1 , .219607843137255 , 0
DATA 1 , .203921568627451 , 0
DATA 1 , .188235294117647 , 0
DATA 1 , .172549019607843 , 0
DATA 1 , .156862745098039 , 0
DATA 1 , .141176470588235 , 0
DATA 1 , .125490196078431 , 0
DATA 1 , .109803921568628 , 0
DATA 1 , 9.41176470588236E-2 , 0
DATA 1 , 7.84313725490198E-2 , 0
DATA 1 , 6.27450980392159E-2 , 0
DATA 1 , 4.70588235294116E-2 , 0
DATA 1 , 3.13725490196077E-2 , 0
DATA 1 , 1.56862745098039E-2 , 0
DATA 1 , 0 , 0
END SUB
EXTERNAL SUB TURBOCOLORMAP
FOR I=0 TO 255
READ R,G,B
SET COLOR MIX(I) R,G,B
NEXT I
DATA 0.18995,0.07176,0.23217
DATA 0.19483,0.08339,0.26149
DATA 0.19956,0.09498,0.29024
DATA 0.20415,0.10652,0.31844
DATA 0.20860,0.11802,0.34607
DATA 0.21291,0.12947,0.37314
DATA 0.21708,0.14087,0.39964
DATA 0.22111,0.15223,0.42558
DATA 0.22500,0.16354,0.45096
DATA 0.22875,0.17481,0.47578
DATA 0.23236,0.18603,0.50004
DATA 0.23582,0.19720,0.52373
DATA 0.23915,0.20833,0.54686
DATA 0.24234,0.21941,0.56942
DATA 0.24539,0.23044,0.59142
DATA 0.24830,0.24143,0.61286
DATA 0.25107,0.25237,0.63374
DATA 0.25369,0.26327,0.65406
DATA 0.25618,0.27412,0.67381
DATA 0.25853,0.28492,0.69300
DATA 0.26074,0.29568,0.71162
DATA 0.26280,0.30639,0.72968
DATA 0.26473,0.31706,0.74718
DATA 0.26652,0.32768,0.76412
DATA 0.26816,0.33825,0.78050
DATA 0.26967,0.34878,0.79631
DATA 0.27103,0.35926,0.81156
DATA 0.27226,0.36970,0.82624
DATA 0.27334,0.38008,0.84037
DATA 0.27429,0.39043,0.85393
DATA 0.27509,0.40072,0.86692
DATA 0.27576,0.41097,0.87936
DATA 0.27628,0.42118,0.89123
DATA 0.27667,0.43134,0.90254
DATA 0.27691,0.44145,0.91328
DATA 0.27701,0.45152,0.92347
DATA 0.27698,0.46153,0.93309
DATA 0.27680,0.47151,0.94214
DATA 0.27648,0.48144,0.95064
DATA 0.27603,0.49132,0.95857
DATA 0.27543,0.50115,0.96594
DATA 0.27469,0.51094,0.97275
DATA 0.27381,0.52069,0.97899
DATA 0.27273,0.53040,0.98461
DATA 0.27106,0.54015,0.98930
DATA 0.26878,0.54995,0.99303
DATA 0.26592,0.55979,0.99583
DATA 0.26252,0.56967,0.99773
DATA 0.25862,0.57958,0.99876
DATA 0.25425,0.58950,0.99896
DATA 0.24946,0.59943,0.99835
DATA 0.24427,0.60937,0.99697
DATA 0.23874,0.61931,0.99485
DATA 0.23288,0.62923,0.99202
DATA 0.22676,0.63913,0.98851
DATA 0.22039,0.64901,0.98436
DATA 0.21382,0.65886,0.97959
DATA 0.20708,0.66866,0.97423
DATA 0.20021,0.67842,0.96833
DATA 0.19326,0.68812,0.96190
DATA 0.18625,0.69775,0.95498
DATA 0.17923,0.70732,0.94761
DATA 0.17223,0.71680,0.93981
DATA 0.16529,0.72620,0.93161
DATA 0.15844,0.73551,0.92305
DATA 0.15173,0.74472,0.91416
DATA 0.14519,0.75381,0.90496
DATA 0.13886,0.76279,0.89550
DATA 0.13278,0.77165,0.88580
DATA 0.12698,0.78037,0.87590
DATA 0.12151,0.78896,0.86581
DATA 0.11639,0.79740,0.85559
DATA 0.11167,0.80569,0.84525
DATA 0.10738,0.81381,0.83484
DATA 0.10357,0.82177,0.82437
DATA 0.10026,0.82955,0.81389
DATA 0.09750,0.83714,0.80342
DATA 0.09532,0.84455,0.79299
DATA 0.09377,0.85175,0.78264
DATA 0.09287,0.85875,0.77240
DATA 0.09267,0.86554,0.76230
DATA 0.09320,0.87211,0.75237
DATA 0.09451,0.87844,0.74265
DATA 0.09662,0.88454,0.73316
DATA 0.09958,0.89040,0.72393
DATA 0.10342,0.89600,0.71500
DATA 0.10815,0.90142,0.70599
DATA 0.11374,0.90673,0.69651
DATA 0.12014,0.91193,0.68660
DATA 0.12733,0.91701,0.67627
DATA 0.13526,0.92197,0.66556
DATA 0.14391,0.92680,0.65448
DATA 0.15323,0.93151,0.64308
DATA 0.16319,0.93609,0.63137
DATA 0.17377,0.94053,0.61938
DATA 0.18491,0.94484,0.60713
DATA 0.19659,0.94901,0.59466
DATA 0.20877,0.95304,0.58199
DATA 0.22142,0.95692,0.56914
DATA 0.23449,0.96065,0.55614
DATA 0.24797,0.96423,0.54303
DATA 0.26180,0.96765,0.52981
DATA 0.27597,0.97092,0.51653
DATA 0.29042,0.97403,0.50321
DATA 0.30513,0.97697,0.48987
DATA 0.32006,0.97974,0.47654
DATA 0.33517,0.98234,0.46325
DATA 0.35043,0.98477,0.45002
DATA 0.36581,0.98702,0.43688
DATA 0.38127,0.98909,0.42386
DATA 0.39678,0.99098,0.41098
DATA 0.41229,0.99268,0.39826
DATA 0.42778,0.99419,0.38575
DATA 0.44321,0.99551,0.37345
DATA 0.45854,0.99663,0.36140
DATA 0.47375,0.99755,0.34963
DATA 0.48879,0.99828,0.33816
DATA 0.50362,0.99879,0.32701
DATA 0.51822,0.99910,0.31622
DATA 0.53255,0.99919,0.30581
DATA 0.54658,0.99907,0.29581
DATA 0.56026,0.99873,0.28623
DATA 0.57357,0.99817,0.27712
DATA 0.58646,0.99739,0.26849
DATA 0.59891,0.99638,0.26038
DATA 0.61088,0.99514,0.25280
DATA 0.62233,0.99366,0.24579
DATA 0.63323,0.99195,0.23937
DATA 0.64362,0.98999,0.23356
DATA 0.65394,0.98775,0.22835
DATA 0.66428,0.98524,0.22370
DATA 0.67462,0.98246,0.21960
DATA 0.68494,0.97941,0.21602
DATA 0.69525,0.97610,0.21294
DATA 0.70553,0.97255,0.21032
DATA 0.71577,0.96875,0.20815
DATA 0.72596,0.96470,0.20640
DATA 0.73610,0.96043,0.20504
DATA 0.74617,0.95593,0.20406
DATA 0.75617,0.95121,0.20343
DATA 0.76608,0.94627,0.20311
DATA 0.77591,0.94113,0.20310
DATA 0.78563,0.93579,0.20336
DATA 0.79524,0.93025,0.20386
DATA 0.80473,0.92452,0.20459
DATA 0.81410,0.91861,0.20552
DATA 0.82333,0.91253,0.20663
DATA 0.83241,0.90627,0.20788
DATA 0.84133,0.89986,0.20926
DATA 0.85010,0.89328,0.21074
DATA 0.85868,0.88655,0.21230
DATA 0.86709,0.87968,0.21391
DATA 0.87530,0.87267,0.21555
DATA 0.88331,0.86553,0.21719
DATA 0.89112,0.85826,0.21880
DATA 0.89870,0.85087,0.22038
DATA 0.90605,0.84337,0.22188
DATA 0.91317,0.83576,0.22328
DATA 0.92004,0.82806,0.22456
DATA 0.92666,0.82025,0.22570
DATA 0.93301,0.81236,0.22667
DATA 0.93909,0.80439,0.22744
DATA 0.94489,0.79634,0.22800
DATA 0.95039,0.78823,0.22831
DATA 0.95560,0.78005,0.22836
DATA 0.96049,0.77181,0.22811
DATA 0.96507,0.76352,0.22754
DATA 0.96931,0.75519,0.22663
DATA 0.97323,0.74682,0.22536
DATA 0.97679,0.73842,0.22369
DATA 0.98000,0.73000,0.22161
DATA 0.98289,0.72140,0.21918
DATA 0.98549,0.71250,0.21650
DATA 0.98781,0.70330,0.21358
DATA 0.98986,0.69382,0.21043
DATA 0.99163,0.68408,0.20706
DATA 0.99314,0.67408,0.20348
DATA 0.99438,0.66386,0.19971
DATA 0.99535,0.65341,0.19577
DATA 0.99607,0.64277,0.19165
DATA 0.99654,0.63193,0.18738
DATA 0.99675,0.62093,0.18297
DATA 0.99672,0.60977,0.17842
DATA 0.99644,0.59846,0.17376
DATA 0.99593,0.58703,0.16899
DATA 0.99517,0.57549,0.16412
DATA 0.99419,0.56386,0.15918
DATA 0.99297,0.55214,0.15417
DATA 0.99153,0.54036,0.14910
DATA 0.98987,0.52854,0.14398
DATA 0.98799,0.51667,0.13883
DATA 0.98590,0.50479,0.13367
DATA 0.98360,0.49291,0.12849
DATA 0.98108,0.48104,0.12332
DATA 0.97837,0.46920,0.11817
DATA 0.97545,0.45740,0.11305
DATA 0.97234,0.44565,0.10797
DATA 0.96904,0.43399,0.10294
DATA 0.96555,0.42241,0.09798
DATA 0.96187,0.41093,0.09310
DATA 0.95801,0.39958,0.08831
DATA 0.95398,0.38836,0.08362
DATA 0.94977,0.37729,0.07905
DATA 0.94538,0.36638,0.07461
DATA 0.94084,0.35566,0.07031
DATA 0.93612,0.34513,0.06616
DATA 0.93125,0.33482,0.06218
DATA 0.92623,0.32473,0.05837
DATA 0.92105,0.31489,0.05475
DATA 0.91572,0.30530,0.05134
DATA 0.91024,0.29599,0.04814
DATA 0.90463,0.28696,0.04516
DATA 0.89888,0.27824,0.04243
DATA 0.89298,0.26981,0.03993
DATA 0.88691,0.26152,0.03753
DATA 0.88066,0.25334,0.03521
DATA 0.87422,0.24526,0.03297
DATA 0.86760,0.23730,0.03082
DATA 0.86079,0.22945,0.02875
DATA 0.85380,0.22170,0.02677
DATA 0.84662,0.21407,0.02487
DATA 0.83926,0.20654,0.02305
DATA 0.83172,0.19912,0.02131
DATA 0.82399,0.19182,0.01966
DATA 0.81608,0.18462,0.01809
DATA 0.80799,0.17753,0.01660
DATA 0.79971,0.17055,0.01520
DATA 0.79125,0.16368,0.01387
DATA 0.78260,0.15693,0.01264
DATA 0.77377,0.15028,0.01148
DATA 0.76476,0.14374,0.01041
DATA 0.75556,0.13731,0.00942
DATA 0.74617,0.13098,0.00851
DATA 0.73661,0.12477,0.00769
DATA 0.72686,0.11867,0.00695
DATA 0.71692,0.11268,0.00629
DATA 0.70680,0.10680,0.00571
DATA 0.69650,0.10102,0.00522
DATA 0.68602,0.09536,0.00481
DATA 0.67535,0.08980,0.00449
DATA 0.66449,0.08436,0.00424
DATA 0.65345,0.07902,0.00408
DATA 0.64223,0.07380,0.00401
DATA 0.63082,0.06868,0.00401
DATA 0.61923,0.06367,0.00410
DATA 0.60746,0.05878,0.00427
DATA 0.59550,0.05399,0.00453
DATA 0.58336,0.04931,0.00486
DATA 0.57103,0.04474,0.00529
DATA 0.55852,0.04028,0.00579
DATA 0.54583,0.03593,0.00638
DATA 0.53295,0.03169,0.00705
DATA 0.51989,0.02756,0.00780
DATA 0.50664,0.02354,0.00863
DATA 0.49321,0.01963,0.00955
DATA 0.47960,0.01583,0.01055
END SUB
Re: wavファイル読み込みルーチン - しばっち
2024/10/13 (Sun) 07:18:01
READWAVルーチン使用例
波形表示
読み込んだwavファイルの波形を表示します。
LET SIZE=44100*200 ! サンプリング周波数44100Hzとして200秒分
DIM LIN(SIZE),RIN(SIZE)
FILE GETOPENNAME F$,"読み込み WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN,ERR)
IF ERR>0 THEN STOP
SET VIEWPORT 0,1,0,.49
SET WINDOW 1,NUM,-1,1
DRAW GRID0(NUM/10,.2)
FOR I=1 TO NUM
PLOT LINES:I,LIN(I);
NEXT I
PLOT LINES
SET VIEWPORT 0,1,.51,1
SET WINDOW 1,NUM,-1,1
DRAW GRID0(NUM/10,.2)
FOR I=1 TO NUM
PLOT LINES:I,RIN(I);
NEXT I
END
以下略
-------------------------------------------------------------------------------------------------
アニメーション波形表示
上記の波形表示をアニメーションで表示します。
但し、リアルタイム表示ではありません。
LET SIZE=44100*200
DIM LIN(SIZE),RIN(SIZE)
FILE GETOPENNAME F$,"読み込み WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN,ERR)
IF ERR>0 THEN STOP
LET ST=SAMPLINGFREQ/30 ! 1/30秒毎
FOR I=1 TO NUM STEP ST
SET VIEWPORT 0,1,0,.49
SET WINDOW 0,ST-1,-1,1
DRAW GRID0(ST/3,.2)
FOR J=0 TO ST-1
PLOT LINES: J,LIN(I+J);
NEXT J
PLOT LINES
SET VIEWPORT 0,1,.51,1
SET WINDOW 0,ST-1,-1,1
DRAW GRID0(ST/3,.2)
FOR J=0 TO ST-1
PLOT LINES: J,RIN(I+J);
NEXT J
SET DRAW MODE EXPLICIT
WAIT DELAY .1
SET DRAW MODE HIDDEN
CLEAR
NEXT I
END
以下略
-------------------------------------------------------------------------------------------------
wavファイルを読み込んでcsvファイルに書き出します。
エクセル等でフィルタ処理等できます。-1~1に正規化されています。
https://decimalbasic.ninja-web.net/log/article/b/basic/105/kdhrmc/wwtchy.html#wwtchy
先頭3秒間を切り出してcsvファイルに書き出します。44100Hz*3秒=132300行
LET SIZE=44100*200
DIM LIN(SIZE),RIN(SIZE)
FILE GETOPENNAME F$,"読み込み WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN,ERR)
IF ERR>0 THEN STOP
IF NUM>SAMPLINGFREQ*3 THEN LET NUM=SAMPLINGFREQ*3 ! 先頭3秒間
FILE GETSAVENAME G$,"保存 CSVファイル|*.CSV"
IF G$="" THEN STOP
CALL WRITECSV(G$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN)
END
以下略
-------------------------------------------------------------------------------------------------
統計でいう平均、分散、標準偏差を求めます。
http://www.gem.hi-ho.ne.jp/joachim/statistics/distance.html?s=euclid1
https://en.wikipedia.org/wiki/Root_mean_square
https://ja.wikipedia.org/wiki/ピーク信号対雑音比
LET SIZE=44100*200
DIM LIN(SIZE),RIN(SIZE)
FILE GETOPENNAME F$,"読み込み WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN,ERR)
IF ERR>0 THEN STOP
PRINT "左チャンネル";MEAN(NUM,LIN);MSE(NUM,LIN);MSER(NUM,LIN)
IF CHANNEL=2 THEN PRINT "右チャンネル";MEAN(NUM,RIN);MSE(NUM,RIN);MSER(NUM,RIN)
END
EXTERNAL FUNCTION MEAN(N,A()) ! 平均
FOR I=1 TO N
LET S=S+A(I)
NEXT I
LET MEAN=S/N
END FUNCTION
EXTERNAL FUNCTION MSE(N,A()) ! 分散
LET M=MEAN(N,A)
FOR I=1 TO N
LET SS=SS+(A(I)-M)^2
NEXT I
LET MSE=SS/N
END FUNCTION
EXTERNAL FUNCTION MSER(N,A()) ! 標準偏差
LET MSER=SQR(MSE(N,A))
END FUNCTION
EXTERNAL FUNCTION RMS(N,A())
FOR I=1 TO N
LET SS=SS+A(I)^2
NEXT I
LET SS=SS/N
LET RMS=20*LOG10(SS)
END FUNCTION
EXTERNAL FUNCTION PEAK(N,A())
FOR I=1 TO N
LET LMAX=MAX(LMAX,ABS(A(I)))
NEXT I
LET PEAK=LMAX
END FUNCTION
以下略
-------------------------------------------------------------------------------------------------
PCMデータを可視化します。
LET SIZE=44100*200
DIM LIN(SIZE),RIN(SIZE)
FILE GETOPENNAME F$,"読み込み WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN,ERR)
IF ERR>0 THEN STOP
LET SIZE=INT(SQR(NUM)+1)
CALL GINIT(SIZE,SIZE*CHANNEL)
FOR Y=0 TO SIZE-1
FOR X=0 TO SIZE-1
LET N=N+1
LET C=INT(LIN(N)*2^23)
IF C<0 THEN LET C=C+2^24
SET POINT COLOR C
PLOT POINTS:X,Y
NEXT X
NEXT Y
IF CHANNEL=2 THEN
LET N=0
FOR Y=SIZE TO 2*SIZE-1
FOR X=0 TO SIZE-1
LET N=N+1
LET C=INT(RIN(N)*2^23)
IF C<0 THEN LET C=C+2^24
SET POINT COLOR C
PLOT POINTS:X,Y
NEXT X
NEXT Y
END IF
END
EXTERNAL SUB GINIT(XSIZE,YSIZE)
SET BITMAP SIZE XSIZE,YSIZE
SET COLOR MIX(0) 0,0,0
SET COLOR MODE "NATIVE"
CLEAR
SET POINT STYLE 1
SET WINDOW 0,XSIZE-1,YSIZE-1,0
END SUB
以下略
-------------------------------------------------------------------------------------------------
カラーマップを定義してPCMデータを可視化します。
LET SIZE=44100*200
DIM LIN(SIZE),RIN(SIZE)
FILE GETOPENNAME F$,"読み込み WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN,ERR)
IF ERR>0 THEN STOP
LET SIZE=INT(SQR(NUM)+1)
CALL GINIT(SIZE,SIZE*CHANNEL)
CALL JETCOLORMAP
FOR Y=0 TO SIZE-1
FOR X=0 TO SIZE-1
LET N=N+1
LET C=INT(LIN(N)*127)+128
CALL PSET(X,Y,C)
NEXT X
NEXT Y
IF CHANNEL=2 THEN
LET N=0
FOR Y=SIZE TO 2*SIZE-1
FOR X=0 TO SIZE-1
LET N=N+1
LET C=INT(RIN(N)*127)+128
CALL PSET(X,Y,C)
NEXT X
NEXT Y
END IF
END
EXTERNAL SUB PSET(X,Y,C)
SET POINT COLOR C
PLOT POINTS:X,Y
END SUB
EXTERNAL SUB GINIT(XSIZE,YSIZE)
SET BITMAP SIZE XSIZE,YSIZE
SET WINDOW 0,XSIZE-1,YSIZE-1,0
SET POINT STYLE 1
SET COLOR MODE "REGULAR"
FOR I=0 TO 7
SET COLOR MIX(I) BITAND(I,2)/2,BITAND(I,4)/4,BITAND(I,1)
NEXT I
CLEAR
END SUB
以下略
Re: wavファイル読み込みルーチン - しばっち
2024/10/13 (Sun) 07:20:14
G711 A-Law、μ-Law形式のwavファイル読み込み
https://ja.wikipedia.org/wiki/G.711
https://ja.wikipedia.org/wiki/Μ-lawアルゴリズム
https://ja.wikipedia.org/wiki/A-lawアルゴリズム
https://www.youfit.co.jp/archives/1416
https://dystopiancode.blogspot.com/2012/02/pcm-law-and-u-law-companding-algorithms.html
このサブルーチンの仕様はREADWAVと同じです。置き換えできます。
EXTERNAL SUB READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN(),RIN(),ERR)
OPTION CHARACTER BYTE
DIM A$(20)
LET ERR=0
WHEN EXCEPTION IN
OPEN #1:NAME F$,ACCESS INPUT !'wavファイル読み込み
USE
LET ERR=2
CLOSE #1
EXIT SUB
END WHEN
FOR I=1 TO 12
CHARACTER INPUT #1:A$(I)
NEXT I
IF A$(1)&A$(2)&A$(3)&A$(4)<>"RIFF" THEN
LET ERR=1
!PRINT "WAVファイルではありません"
CLOSE #1
EXIT SUB
END IF
LET WAVEFILESIZE=INT32(A$(5)&A$(6)&A$(7)&A$(8))
IF A$(9)&A$(10)&A$(11)&A$(12)<>"WAVE" THEN
LET ERR=1
PRINT "WAVファイルではありません"
CLOSE #1
EXIT SUB
END IF
DO
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
SELECT CASE A$(1)&A$(2)&A$(3)&A$(4)
CASE "fmt "
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET HEADERSIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
FOR I=1 TO HEADERSIZE
CHARACTER INPUT #1:A$(I)
NEXT I
LET WAVETYPE=INT16(A$(1)&A$(2))
IF WAVETYPE<>7 AND WAVTYPE<>6 THEN
LET ERR=1
! PRINT "対応していません"
CLOSE #1
EXIT SUB
END IF
LET CHANNEL=INT16(A$(3)&A$(4))
LET SAMPLINGFREQ=INT32(A$(5)&A$(6)&A$(7)&A$(8))
LET DATARATE=INT32(A$(9)&A$(10)&A$(11)&A$(12))
LET SAMPLESIZE=INT16(A$(13)&A$(14))
LET SAMPLEBIT=INT16(A$(15)&A$(16))
CASE "data"
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET PCMSIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
LET SECOND=PCMSIZE/DATARATE
!' LET NUM=INT(SAMPLINGFREQ*SECOND)
LET NUM=PCMSIZE/SAMPLESIZE
EXIT DO
CASE "fact"
FOR I=1 TO 8
CHARACTER INPUT #1:A$(I)
NEXT I
!' LET SIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
!' LET SAMPLE=INT32(A$(5)&A$(6)&A$(7)&A$(8))
CASE "LIST"
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET SIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
FOR I=1 TO SIZE
CHARACTER INPUT #1:DMY$
NEXT I
CASE ELSE
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET SIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
FOR I=1 TO SIZE
CHARACTER INPUT #1:DMY$
NEXT I
END SELECT
LOOP
!REDIM LIN(NUM)
!REDIM RIN(NUM)
LET A=INT(NUM/100)
PRINT "読み込み中"
FOR K=1 TO NUM
IF MOD(K,INT(NUM/A))=0 AND INT(K/A)<>R THEN
LET R=INT(K/A)
PRINT R;"%"
END IF
FOR CH=1 TO CHANNEL
CHARACTER INPUT #1:B$
IF WAVETYPE=7 THEN LET DAT=MULAWDECODE(ORD(B$))
IF WAVETYPE=6 THEN LET DAT=ALAWDECODE(ORD(B$))
SELECT CASE CH
CASE 1
LET LIN(K)=DAT
CASE 2
LET RIN(K)=DAT
CASE ELSE
END SELECT
NEXT CH
NEXT K
CLOSE #1
END SUB
EXTERNAL FUNCTION MULAWDECODE(INDEX) ! μLawデコード
RESTORE
FOR I=0 TO INDEX
READ X
NEXT I
LET MULAWDECODE=X/8192
DATA -8031 ,-7775 ,-7519 ,-7263 ,-7007 ,-6751 ,-6495 ,-6239 ,-5983 ,-5727 ,-5471 ,-5215 ,-4959 ,-4703 ,-4447 ,-4191
DATA -3999 ,-3871 ,-3743 ,-3615 ,-3487 ,-3359 ,-3231 ,-3103 ,-2975 ,-2847 ,-2719 ,-2591 ,-2463 ,-2335 ,-2207 ,-2079
DATA -1983 ,-1919 ,-1855 ,-1791 ,-1727 ,-1663 ,-1599 ,-1535 ,-1471 ,-1407 ,-1343 ,-1279 ,-1215 ,-1151 ,-1087 ,-1023
DATA -975 , -943 , -911 , -879 , -847 , -815 , -783 , -751 , -719 , -687 , -655 , -623 , -591 , -559 , -527 , -495
DATA -471 , -455 , -439 , -423 , -407 , -391 , -375 , -359 , -343 , -327 , -311 , -295 , -279 , -263 , -247 , -231
DATA -219 , -211 , -203 , -195 , -187 , -179 , -171 , -163 , -155 , -147 , -139 , -131 , -123 , -115 , -107 , -99
DATA -93 , -89 , -85 , -81 , -77 , -73 , -69 , -65 , -61 , -57 , -53 , -49 , -45 , -41 , -37 , -33
DATA -30 , -28 , -26 , -24 , -22 , -20 , -18 , -16 , -14 , -12 , -10 , -8 , -6 , -4 , -2 , 0
DATA 8031 , 7775 , 7519 , 7263 , 7007 , 6751 , 6495 , 6239 , 5983 , 5727 , 5471 , 5215 , 4959 , 4703 , 4447 , 4191
DATA 3999 , 3871 , 3743 , 3615 , 3487 , 3359 , 3231 , 3103 , 2975 , 2847 , 2719 , 2591 , 2463 , 2335 , 2207 , 2079
DATA 1983 , 1919 , 1855 , 1791 , 1727 , 1663 , 1599 , 1535 , 1471 , 1407 , 1343 , 1279 , 1215 , 1151 , 1087 , 1023
DATA 975 , 943 , 911 , 879 , 847 , 815 , 783 , 751 , 719 , 687 , 655 , 623 , 591 , 559 , 527 , 495
DATA 471 , 455 , 439 , 423 , 407 , 391 , 375 , 359 , 343 , 327 , 311 , 295 , 279 , 263 , 247 , 231
DATA 219 , 211 , 203 , 195 , 187 , 179 , 171 , 163 , 155 , 147 , 139 , 131 , 123 , 115 , 107 , 99
DATA 93 , 89 , 85 , 81 , 77 , 73 , 69 , 65 , 61 , 57 , 53 , 49 , 45 , 41 , 37 , 33
DATA 30 , 28 , 26 , 24 , 22 , 20 , 18 , 16 , 14 , 12 , 10 , 8 , 6 , 4 , 2 , 0
END FUNCTION
EXTERNAL FUNCTION ALAWDECODE(INDEX) ! A-Lawデコード
RESTORE
FOR I=0 TO INDEX
READ X
NEXT I
LET ALAWDECODE=X/4096
DATA 688 , 656 , 752 , 720 , 560 , 528 , 624 , 592 , 944 , 912 , 1008 , 976 , 816 , 784 , 880 , 848
DATA 344 , 328 , 376 , 360 , 280 , 264 , 312 , 296 , 472 , 456 , 504 , 488 , 408 , 392 , 440 , 424
DATA 2752 , 2624 , 3008 , 2880 , 2240 , 2112 , 2496 , 2368 , 3776 , 3648 , 4032 , 3904 , 3264 , 3136 , 3520 , 3392
DATA 1376 , 1312 , 1504 , 1440 , 1120 , 1056 , 1248 , 1184 , 1888 , 1824 , 2016 , 1952 , 1632 , 1568 , 1760 , 1696
DATA 43 , 41 , 47 , 45 , 35 , 33 , 39 , 37 , 59 , 57 , 63 , 61 , 51 , 49 , 55 , 53
DATA 11 , 9 , 15 , 13 , 3 , 1 , 7 , 5 , 27 , 25 , 31 , 29 , 19 , 17 , 23 , 21
DATA 172 , 164 , 188 , 180 , 140 , 132 , 156 , 148 , 236 , 228 , 252 , 244 , 204 , 196 , 220 , 212
DATA 86 , 82 , 94 , 90 , 70 , 66 , 78 , 74 , 118 , 114 , 126 , 122 , 102 , 98 , 110 , 106
DATA -688 , -656 , -752 , -720 , -560 , -528 , -624 , -592 , -944 , -912 ,-1008 , -976 , -816 , -784 , -880 , -848
DATA -344 , -328 , -376 , -360 , -280 , -264 , -312 , -296 , -472 , -456 , -504 , -488 , -408 , -392 , -440 , -424
DATA -2752 ,-2624 ,-3008 ,-2880 ,-2240 ,-2112 ,-2496 ,-2368 ,-3776 ,-3648 ,-4032 ,-3904 ,-3264 ,-3136 ,-3520 ,-3392
DATA -1376 ,-1312 ,-1504 ,-1440 ,-1120 ,-1056 ,-1248 ,-1184 ,-1888 ,-1824 ,-2016 ,-1952 ,-1632 ,-1568 ,-1760 ,-1696
DATA -43 , -41 , -47 , -45 , -35 , -33 , -39 , -37 , -59 , -57 , -63 , -61 , -51 , -49 , -55 , -53
DATA -11 , -9 , -15 , -13 , -3 , -1 , -7 , -5 , -27 , -25 , -31 , -29 , -19 , -17 , -23 , -21
DATA -172 , -164 , -188 , -180 , -140 , -132 , -156 , -148 , -236 , -228 , -252 , -244 , -204 , -196 , -220 , -212
DATA -86 , -82 , -94 , -90 , -70 , -66 , -78 , -74 , -118 , -114 , -126 , -122 , -102 , -98 , -110 , -106
END FUNCTION
!EXTERNAL FUNCTION MULAWDECODE(X) ! 0<=X<=255
!LET X=INT(X)
!LET S=MUDECODE(X)
!LET MULAWDECODE=S/8192
!
!FUNCTION MUDECODE(X)
! ASSIGN ".\DLL\g711.dll","MuLaw_Decode"
!END FUNCTION
!END FUNCTION
!EXTERNAL FUNCTION ALAWDECODE(X) ! 0<=X<=255
!LET X=INT(X)
!LET ALAWDECODE=ADECODE(X)/32768
!
!FUNCTION ADECODE(X)
! ASSIGN ".\DLL\g711.dll","ALaw_Decode"
!END FUNCTION
!END FUNCTION
以下略
-----------------------------------------------------------------------------------------
g711.c
#include <stdint.h>
__declspec(dllexport) int ALaw_Encode(int number)
{
const uint16_t ALAW_MAX = 0xFFF;
uint16_t mask = 0x800;
uint8_t sign = 0;
uint8_t position = 11;
uint8_t lsb = 0;
if (number < 0)
{
number = -number;
sign = 0x80;
}
if (number > ALAW_MAX)
{
number = ALAW_MAX;
}
for (; ((number & mask) != mask && position >= 5); mask >>= 1, position--);
lsb = (number >> ((position == 4) ? (1) : (position - 4))) & 0x0f;
return (sign | ((position - 4) << 4) | lsb) ^ 0x55;
}
__declspec(dllexport) int ALaw_Decode(int number)
{
uint8_t sign = 0x00;
uint8_t position = 0;
int16_t decoded = 0;
number ^= 0x55;
if (number & 0x80)
{
number &= ~(1 << 7);
sign = -1;
}
position = ((number & 0xF0) >> 4) + 4;
if (position != 4)
{
decoded = ((1 << position) | ((number & 0x0F) << (position - 4))
| (1 << (position - 5)));
}
else
{
decoded = (number << 1) | 1;
}
return (sign == 0) ? (decoded) : (-decoded);
}
__declspec(dllexport) int MuLaw_Encode(int number)
{
const uint16_t MULAW_MAX = 0x1FFF;
const uint16_t MULAW_BIAS = 33;
uint16_t mask = 0x1000;
uint8_t sign = 0;
uint8_t position = 12;
uint8_t lsb = 0;
if (number < 0)
{
number = -number;
sign = 0x80;
}
number += MULAW_BIAS;
if (number > MULAW_MAX)
{
number = MULAW_MAX;
}
for (; ((number & mask) != mask && position >= 5); mask >>= 1, position--)
;
lsb = (number >> (position - 4)) & 0x0f;
return (~(sign | ((position - 5) << 4) | lsb));
}
__declspec(dllexport) int MuLaw_Decode(int number)
{
const uint16_t MULAW_BIAS = 33;
uint8_t sign = 0, position = 0;
int16_t decoded = 0;
number = ~number;
if (number & 0x80)
{
number &= ~(1 << 7);
sign = -1;
}
position = ((number & 0xF0) >> 4) + 5;
decoded = ((1 << position) | ((number & 0x0F) << (position - 4))
| (1 << (position - 5))) - MULAW_BIAS;
return (sign == 0) ? (decoded) : (-(decoded));
}
Re: wavファイル読み込みルーチン - しばっち
2024/10/13 (Sun) 07:21:23
au/sndファイルの読み込み
全てのau/sndファイルが読み込めるわけではありません。
ERR>0の時は読み込みに失敗しています。
このサブルーチンの仕様はREADWAVと同じです。つまりCALL READWAV(...をCALL READSND(...と置き換えできます。
EXTERNAL SUB READSND(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN(),RIN(),ERR)
OPTION CHARACTER BYTE
DIM A$(24)
LET ERR=0
OPEN #1:NAME F$,ACCESS INPUT
ASK #1:FILESIZE SIZE
IF SIZE=0 THEN
CLOSE #1
LET ERR=4
EXIT SUB
END IF
LET SIZE=SIZE-24
FOR I=1 TO 24
CHARACTER INPUT #1:A$(I)
NEXT I
IF A$(1)&A$(2)&A$(3)&A$(4)<>".snd" THEN
!PRINT "AUファイルではありません"
CLOSE #1
LET ERR=3
EXIT SUB
END IF
LET OFFSET=CVL2(A$(5)&A$(6)&A$(7)&A$(8))
IF OFFSET<>24 THEN
!PRINT "対応していません"
LET ERR=2
CLOSE #1
EXIT SUB
END IF
LET DATASIZE=CVL2(A$(9)&A$(10)&A$(11)&A$(12))
LET ENCODING=CVL2(A$(13)&A$(14)&A$(15)&A$(16))
IF ENCODING<>2 AND ENCODING<>3 AND ENCODING<>4 AND ENCODING<>5 THEN
!PRINT "対応していません"
LET ERR=2
CLOSE #1
EXIT SUB
END IF
LET SAMPLINGFREQ=CVL2(A$(17)&A$(18)&A$(19)&A$(20))
LET CHANNEL=CVL2(A$(21)&A$(22)&A$(23)&A$(24))
IF CHANNEL<>1 AND CHANNEL<>2 THEN
!PRINT "対応していません"
LET ERR=2
CLOSE #1
EXIT SUB
END IF
IF ENCODING=2 THEN LET SAMPLEBIT=8
IF ENCODING=3 THEN LET SAMPLEBIT=16
IF ENCODING=4 THEN LET SAMPLEBIT=24
IF ENCODING=5 THEN LET SAMPLEBIT=32
LET SAMPLESIZE=SAMPLEBIT/8*CHANNEL
LET NUM=SIZE/SAMPLESIZE
!REDIM LIN(NUM)
!REDIM RIN(NUM)
LET A=INT(NUM/100)
PRINT "読み込み中"
LET B$=REPEAT$(" ",4)
FOR K=1 TO NUM
IF MOD(K,INT(NUM/A))=0 AND INT(K/A)<>R THEN
LET R=INT(K/A)
PRINT R;"%"
END IF
FOR CH=1 TO CHANNEL
FOR J=1 TO SAMPLEBIT/8
CHARACTER INPUT #1:B$(J:J)
NEXT J
SELECT CASE CH
CASE 1
SELECT CASE SAMPLEBIT
CASE 8
LET LIN(K)=(ORD(B$(1:1))-128)/128
CASE 16
LET LIN(K)=CVI2(B$(1:2))/2^15
CASE 24
LET LIN(K)=CVM2(B$(1:3))/2^23
CASE 32
LET LIN(K)=CVL2(B$)/2^31
END SELECT
CASE 2
SELECT CASE SAMPLEBIT
CASE 8
LET RIN(K)=(ORD(B$(1:1))-128)/128
CASE 16
LET RIN(K)=CVI2(B$(1:2))/2^15
CASE 24
LET RIN(K)=CVM2(B$(1:3))/2^23
CASE 32
LET RIN(K)=CVL2(B$)/2^31
END SELECT
CASE ELSE
END SELECT
NEXT CH
NEXT K
CLOSE #1
END SUB
EXTERNAL FUNCTION CVI2(A$) !BIG-ENDIAN
OPTION CHARACTER BYTE
DECLARE NUMERIC A
LET A$=LEFT$(A$,2)
LET A=ORD(A$(1:1))*256+ORD(A$(2:2))
IF A>32767 THEN LET A=A-65536
LET CVI2=A
END FUNCTION
EXTERNAL FUNCTION CVL2(A$) !BIG-ENDIAN
OPTION CHARACTER BYTE
DECLARE NUMERIC A
LET A$=LEFT$(A$,4)
LET A=ORD(A$(1:1))*256^3+ORD(A$(2:2))*256^2+ORD(A$(3:3))*256+ORD(A$(4:4))
IF A>=2^31-1 THEN LET A=A-2^32
LET CVL2=A
END FUNCTION
EXTERNAL FUNCTION CVM2(A$) !BIG-ENDIAN
OPTION CHARACTER BYTE
DECLARE NUMERIC A
LET A$=LEFT$(A$,3)
LET A=ORD(A$(1:1))*256^2+ORD(A$(2:2))*256+ORD(A$(3:3))
IF A>=2^23-1 THEN LET A=A-2^24
LET CVM2=A
END FUNCTION
----------------------------------------------------------------------
使用例
au/sndファイルからwavファイルに変換します。
LET SAMPLINGFREQ=44100
LET NUM=SAMPLINGFREQ*200
DIM LIN(NUM),RIN(NUM)
FILE GETOPENNAME F$,"読み込み AU/SNDファイル|*.au;*.snd"
IF F$="" THEN STOP
CALL READSND(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN)
FILE GETSAVENAME F$,"保存 WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL WRITEWAV(F$,NUM,CHANNEL,SAMPLEFREQ,SAMPLEBIT,LIN,RIN)
END
以下略
Re: wavファイル読み込みルーチン - しばっち
2024/10/13 (Sun) 07:22:46
aiffファイル読み込み
全てのaif/aiffファイルが読み込めるわけではありません。aifcファイルは圧縮形式のため読めません。
ERR>0の時は読み込みに失敗しています。
このサブルーチンの仕様はREADWAVと同じです。つまりCALL READWAV(...をCALL READAIFF(...と置き換えできます。
EXTERNAL SUB READAIFF(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN(),RIN(),ERR)
OPTION CHARACTER BYTE
DIM A$(22)
LET ERR=0
WHEN EXCEPTION IN
OPEN #1:NAME F$,ACCESS INPUT !'aiffファイル読み込み
USE
LET ERR=2
CLOSE #1
EXIT SUB
END WHEN
FOR I=1 TO 12
CHARACTER INPUT #1:A$(I)
NEXT I
IF A$(1)&A$(2)&A$(3)&A$(4)<>"FORM" THEN
LET ERR=1
!PRINT "AIFFファイルではありません"
CLOSE #1
EXIT SUB
END IF
LET SIZE=INT32(A$(5)&A$(6)&A$(7)&A$(8))
IF A$(9)&A$(10)&A$(11)&A$(12)<>"AIFF" THEN
LET ERR=1
!PRINT "AIFFファイルではありません"
CLOSE #1
EXIT SUB
END IF
DO
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
SELECT CASE A$(1)&A$(2)&A$(3)&A$(4)
CASE "COMM"
FOR I=1 TO 22
CHARACTER INPUT #1:A$(I)
NEXT I
LET SIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
LET CHANNEL=INT16(A$(5)&A$(6))
LET NUM=INT32(A$(7)&A$(8)&A$(9)&A$(10))
LET SAMPLEBIT=INT16(A$(11)&A$(12))
LET SAMPLINGFREQ=FLOAT80(A$(13)&A$(14)&A$(15)&A$(16)&A$(17)&A$(18)&A$(19)&A$(20)&A$(21)&A$(22))
CASE "SSND"
FOR I=1 TO 12
CHARACTER INPUT #1:A$(I)
NEXT I
LET SIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
LET OFFSET=INT32(A$(5)&A$(6)&A$(7)&A$(8))
LET BLOCKSIZE=INT32(A$(9)&A$(10)&A$(11)&A$(12))
EXIT DO
CASE ELSE
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET SIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
FOR I=1 TO SIZE
CHARACTER INPUT #1:DMY$
NEXT I
END SELECT
LOOP
!REDIM LIN(NUM)
!REDIM RIN(NUM)
LET A=INT(NUM/100)
PRINT "読み込み中"
LET B$=REPEAT$(" ",4)
FOR K=1 TO NUM
IF MOD(K,INT(NUM/A))=0 AND INT(K/A)<>R THEN
LET R=INT(K/A)
PRINT R;"%"
END IF
FOR CH=1 TO CHANNEL
FOR J=1 TO SAMPLEBIT/8
CHARACTER INPUT #1:B$(J:J)
NEXT J
SELECT CASE SAMPLEBIT
CASE 8
LET DAT=(ORD(B$(1:1))-128)/128
CASE 16
LET DAT=INT16(B$(1:2))/2^15
CASE 24
LET DAT=INT24(B$(1:3))/2^23
CASE 32
LET DAT=INT32(B$(1:4))/2^31
END SELECT
SELECT CASE CH
CASE 1
LET LIN(K)=DAT
CASE 2
LET RIN(K)=DAT
CASE ELSE
END SELECT
NEXT CH
NEXT K
CLOSE #1
END SUB
EXTERNAL FUNCTION INT16(X$) ! BIG-ENDIAN
OPTION CHARACTER BYTE
FOR I=1 TO 2
LET S=S*256+ORD(X$(I:I))
NEXT I
LET INT16=S
END FUNCTION
EXTERNAL FUNCTION INT24(X$) ! BIG-ENDIAN
OPTION CHARACTER BYTE
FOR I=1 TO 3
LET S=S*256+ORD(X$(I:I))
NEXT I
LET INT24=S
END FUNCTION
EXTERNAL FUNCTION INT32(X$) ! BIG-ENDIAN
OPTION CHARACTER BYTE
FOR I=1 TO 4
LET S=S*256+ORD(X$(I:I))
NEXT I
LET INT32=S
END FUNCTION
EXTERNAL FUNCTION FLOAT80(A$)
!'モトローラIEEE754 80bit FLOAT
OPTION BASE 0
OPTION CHARACTER BYTE
DIM B(80)
LET K=0
FOR I=1 TO 10
LET D$=MID$(A$,I,1)
FOR J=0 TO 7
IF BITAND(ORD(D$),2^(7-J))<>0 THEN LET B(K)=1 ELSE LET B(K)=0
LET K=K+1
NEXT J
NEXT I
FOR I=1 TO 15
LET E=E+B(I)*2^(15-I)
NEXT I
LET E=E-16382
LET S=0
FOR I=16 TO 80
LET S=S+B(I)*2^(15-I)
NEXT I
LET X=2^E*S
IF B(0)=1 THEN LET X=-X
LET FLOAT80=X
END FUNCTION
Re: wavファイル読み込みルーチン - しばっち
2024/10/13 (Sun) 07:24:11
csvファイル読み込み
読み込めるフォーマットはサンプリング周波数、サンプルビット、チャンネル数、サンプル数に続いて2chまでのPCMデータです。
マルチチャンネルには対応していません。
ERR>0の時は読み込み失敗しています。
このサブルーチンの仕様はREADWAVと同じです。置き換えできます。
EXTERNAL SUB READCSV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN(),RIN(),ERR)
LET ERR=0
WHEN EXCEPTION IN
OPEN #1:NAME F$
ASK #1: FILESIZE SIZE
USE
LET ERR=3
CLOSE #1
EXIT SUB
END WHEN
IF SIZE=0 THEN
LET ERR=2
CLOSE #1
EXIT SUB
END IF
INPUT #1:SAMPLINGFREQ ! サンプリング周波数
INPUT #1:SAMPLEBIT ! サンプルビット
INPUT #1:CHANNEL ! チャンネル数
INPUT #1:NUM ! サンプル数
!REDIM LIN(NUM)
!REDIM RIN(NUM)
LET A=INT(NUM/100)
PRINT "読み込み中"
FOR K=1 TO NUM
IF MOD(K,INT(NUM/A))=0 AND INT(K/A)<>R THEN
LET R=INT(K/A)
PRINT R;"%"
END IF
SELECT CASE CHANNEL
CASE 1
INPUT #1:LIN(K)
CASE 2
INPUT #1:LIN(K),RIN(K)
CASE ELSE
!PRINT "3ch以上には対応していません"
CLOSE #1
LET ERR=1
EXIT SUB
END SELECT
NEXT K
CLOSE #1
END SUB
----------------------------------------------------------------------------------
READCSVルーチン使用例
csvファイルを読み込んでwavファイルを書き出します。
LET NUM=44100*10
DIM LIN(NUM),RIN(NUM)
FILE GETOPENNAME F$,"読み込み CSVファイル|*.CSV"
IF F$="" THEN STOP
CALL READCSV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN,ERR)
IF ERR>0 THEN STOP
FILE GETSAVENAME G$,"保存 WAVファイル|*.WAV"
IF G$="" THEN STOP
CALL WRITEWAV(G$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN)
END
以下略
----------------------------------------------------------------------------------
切り出し機能をつけてみた。
STARTTIMEに開始時間をENDTIMEに終了時間を指定すると切り出しできます。
負数を指定すると無効になります。
EXTERNAL SUB READCSV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN(),RIN(),ERR,STARTTIME,ENDTIME)
LET ERR=0
WHEN EXCEPTION IN
OPEN #1:NAME F$
ASK #1: FILESIZE SIZE
CLOSE #1
USE
LET ERR=3
EXIT SUB
END WHEN
IF SIZE=0 THEN
LET ERR=2
EXIT SUB
END IF
OPEN #1:NAME F$
INPUT #1:SAMPLINGFREQ
INPUT #1:SAMPLEBIT
INPUT #1:CHANNEL
INPUT #1:NUM
IF STARTTIME>=0 THEN LET FS=SAMPLINGFREQ*STARTTIME ELSE LET FS=1
IF ENDTIME>0 THEN LET FE=SAMPLINGFREQ*ENDTIME ELSE LET FE=NUM
IF FE>NUM THEN LET FE=NUM
LET A=INT(NUM/100)
PRINT "読み込み中"
FOR K=1 TO NUM
IF MOD(K,INT(NUM/A))=0 AND INT(K/A)<>R THEN
LET R=INT(K/A)
PRINT R;"%"
END IF
SELECT CASE CHANNEL
CASE 1
INPUT #1:L
IF K>=FS AND K<=FE THEN
LET N=N+1
LET LIN(N)=L
END IF
CASE 2
INPUT #1:L,R
IF K>=FS AND K<=FE THEN
LET N=N+1
LET LIN(N)=L
LET RIN(N)=R
END IF
CASE ELSE
!PRINT "対応していません"
CLOSE #1
LET ERR=1
EXIT SUB
END SELECT
NEXT K
LET NUM=N
CLOSE #1
END SUB
----------------------------------------------------------------------------------
使用例
LET NUM=44100*200
DIM LIN(NUM),RIN(NUM)
FILE GETOPENNAME F$,"読込み CSVファイル|*.csv"
IF F$="" THEN STOP
CALL READCSV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN,ERR,-1,-1) ! 切り出し無効
!CALL READCSV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN,ERR,3,5) ! 3秒から5秒までを切り出し。
IF ERR>0 THEN STOP
以下略
Re: wavファイル読み込みルーチン - しばっち
2024/10/13 (Sun) 07:26:12
rawファイル読み込み
ヘッダーはなく、PCMデータのみの読み込みです。
BIG-ENDIANに対応しています。
このサブルーチンの仕様はREADWAVと一部異なりますが置き換えできます。
EXTERNAL SUB READRAW(F$,NUM,CHANNEL,SAMPLEBIT,LIN(),RIN(),BIGENDIAN,ERR)
OPTION CHARACTER BYTE
LET ERR=0
WHEN EXCEPTION IN
OPEN #1:NAME F$,ACCESS INPUT !'rawファイル読み込み
ASK #1:FILESIZE SIZE
USE
LET ERR=2
CLOSE #1
EXIT SUB
END WHEN
IF SIZE=0 THEN
LET ERR=1
CLOSE #1
EXIT SUB
END IF
LET NUM=SIZE/CHANNEL/(SAMPLEBIT/8)
LET B$=REPEAT$(CHR$(0),8)
!REDIM LIN(NUM)
!REDIM RIN(NUM)
LET A=INT(NUM/100)
PRINT "読み込み中"
FOR K=1 TO NUM
IF MOD(K,INT(NUM/A))=0 AND INT(K/A)<>R THEN
LET R=INT(K/A)
PRINT R;"%"
END IF
FOR CH=1 TO CHANNEL
FOR J=1 TO SAMPLEBIT/8
CHARACTER INPUT #1:B$(J:J)
NEXT J
SELECT CASE SAMPLEBIT
CASE 8
LET DAT=(ORD(B$(1:1))-128)/2^7
CASE 16
IF BIGENDIAN<>0 THEN LET B$=B$(2:2)&B$(1:1)
LET DAT=INT16(B$)/2^15
CASE 24
IF BIGENDIAN<>0 THEN LET B$=B$(3:3)&B$(2:2)&B$(1:1)
LET DAT=INT24(B$)/2^23
CASE 32
IF BIGENDIAN<>0 THEN LET B$=B$(4:4)&B$(3:3)&B$(2:2)&B$(1:1)
LET DAT=INT32(B$)/2^31
!CASE 64
! IF BIGENDIAN<>0 THEN LET B$=B$(8:8)&B$(7:7)&B$(6:6)&B$(5:5)&B$(4:4)&B$(3:3)&B$(2:2)&B$(1:1)
! LET DAT=INT64(B$)/2^63
END SELECT
SELECT CASE CH
CASE 1
LET LIN(K)=DAT
CASE 2
LET RIN(K)=DAT
CASE ELSE
END SELECT
NEXT CH
NEXT K
CLOSE #1
END SUB
以下略
------------------------------------------------------------------------------
READRAWルーチン使用例
ヘッダーがないので読み込み前にサンプルビットや
チャンネル数を指定する必要があります。
LET SIZE=44100*200
DIM LIN(SIZE),RIN(SIZE)
FILE GETOPENNAME F$,"読み込み RAWファイル|*.RAW"
IF F$="" THEN STOP
INPUT PROMPT "チャンネル数=":CHANNEL ! 1 or 2
INPUT PROMPT "サンプルビット=":SAMPLEBIT ! 8,16,24,32,64
CALL READRAW(F$,NUM,CHANNEL,SAMPLEBIT,LIN,RIN,0,ERR)
IF ERR>0 THEN STOP
Re: wavファイル読み込みルーチン - しばっち
2024/10/13 (Sun) 07:27:20
WAVINFOデータ読み込み
PCMデータは読み込みません。ヘッダーのみの読み出しです。
wavファイルの仕様を調べるのに使用します。
https://forest.watch.impress.co.jp/library/software/mediainfo/
https://kurohane.net/seisanbutu.html
EXTERNAL SUB READWAVINFO(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,WAVETYPE$,DATARATE,PCMSIZE,PLAYTIME,ERR)
OPTION CHARACTER BYTE
DIM A$(40)
LET ERR=0
WHEN EXCEPTION IN
OPEN #1:NAME F$,ACCESS INPUT !'wavファイル読み込み
USE
LET ERR=2
CLOSE #1
EXIT SUB
END WHEN
FOR I=1 TO 12
CHARACTER INPUT #1:A$(I)
NEXT I
IF A$(1)&A$(2)&A$(3)&A$(4)<>"RIFF" THEN
LET ERR=1
PRINT "WAVファイルではありません"
CLOSE #1
EXIT SUB
END IF
LET WAVEFILESIZE=INT32(A$(5)&A$(6)&A$(7)&A$(8))
IF A$(9)&A$(10)&A$(11)&A$(12)<>"WAVE" THEN
LET ERR=1
PRINT "WAVファイルではありません"
CLOSE #1
EXIT SUB
END IF
DO
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
SELECT CASE A$(1)&A$(2)&A$(3)&A$(4)
CASE "fmt "
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET HEADERSIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
FOR I=1 TO HEADERSIZE
CHARACTER INPUT #1:A$(I)
NEXT I
IF HEADERSIZE=16 OR HEADERSIZE=18 THEN
LET WAVETYPE=INT16(A$(1)&A$(2))
LET CHANNEL=INT16(A$(3)&A$(4))
LET SAMPLINGFREQ=INT32(A$(5)&A$(6)&A$(7)&A$(8))
LET DATARATE=INT32(A$(9)&A$(10)&A$(11)&A$(12))
LET SAMPLESIZE=INT16(A$(13)&A$(14))
LET SAMPLEBIT=INT16(A$(15)&A$(16))
IF HEADERSIZE=18 THEN LET CBSIZE=INT16(A$(17)&A$(18))
SELECT CASE WAVETYPE
CASE 0
LET WAVETYPE$="Unknown"
CASE 1
LET WAVETYPE$="PCM"
CASE 2
LET WAVETYPE$="MS-ADPCM"
CASE 3
LET WAVETYPE$="IEEE754-浮動小数"
CASE 5
LET WAVETYPE$="IBM-CSVD"
CASE 6
LET WAVETYPE$="G711-A-Law"
CASE 7
LET WAVETYPE$="G711-μ-Law"
CASE 16
LET WAVETYPE$="OKI-ADPCM"
CASE 17
LET WAVETYPE$="IMA-ADPCM"
CASE 18
LET WAVETYPE$="MediaSpace-ADPCM"
CASE 19
LET WAVETYPE$="Sierra-ADPCM"
CASE 20
LET WAVETYPE$="G723-ADPCM"
CASE ELSE
LET WAVETYPE$=""
END SELECT
ELSEIF HEADERSIZE=40 THEN ! 拡張フォーマット
LET TMP=INT16(A$(1)&A$(2))
LET CHANNEL=INT16(A$(3)&A$(4))
LET SAMPLINGFREQ=INT32(A$(5)&A$(6)&A$(7)&A$(8))
LET COMPRESS=INT32(A$(9)&A$(10)&A$(11)&A$(12))
LET SAMPLESIZE=INT16(A$(13)&A$(14))
LET SAMPLEBIT=INT16(A$(15)&A$(16))
LET CBSIZE=INT16(A$(17)&A$(18))
LET BITPERSAMPLE=INT16(A$(19)&A$(20))
LET CHANNELMASK=INT32(A$(21)&A$(22)&A$(23)&A$(24))
END IF
CASE "data"
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET PCMSIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
IF DATARATE>0 THEN LET PLAYTIME=PCMSIZE/DATARATE
LET NUM=PCMSIZE/SAMPLESIZE
EXIT DO
CASE "fact"
FOR I=1 TO 8
CHARACTER INPUT #1:A$(I)
NEXT I
!' LET SIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
!' LET SAMPLE=INT32(A$(5)&A$(6)&A$(7)&A$(8))
CASE "JUNK"
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET SIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
FOR I=1 TO SIZE
CHARACTER INPUT #1:DMY$
NEXT I
CASE ELSE
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET SIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
FOR I=1 TO SIZE
CHARACTER INPUT #1:DMY$
NEXT I
END SELECT
LOOP
CLOSE #1
END SUB
以下略
-------------------------------------------------------------------
使用例
wavファイルの形式、チャンネル数やサンプリング周波数等を付加したファイル名にリネームします。
FILE GETOPENNAME F$,"読み込み WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL READWAVINFO(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,WAVETYPE$,DATARATE,PCMSIZE,PLAYTIME,ERR)
IF ERR>0 THEN STOP
FILE SPLITNAME (F$) PATH$, NAME$, EXT$
LET G$=PATH$&NAME$&"_"&WAVETYPE$&"_"&STR$(CHANNEL)&"ch_"&STR$(SAMPLINGFREQ)&"Hz_"&STR$(SAMPLEBIT)&"bit_"&STR$(INT(PLAYTIME))&"秒.wav"
FILE RENAME F$,G$
END
以下略
Re: wavファイル読み込みルーチン - しばっち
2024/10/13 (Sun) 07:28:28
wavファイルの仕様を表示します。
FILE GETOPENNAME F$,"WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL WAVINFODISPLAY(F$)
END
EXTERNAL SUB WAVINFODISPLAY(F$)
OPTION CHARACTER BYTE
DIM A$(40)
LET ERR=0
WHEN EXCEPTION IN
OPEN #1:NAME F$,ACCESS INPUT !'wavファイル読み込み
USE
PRINT "読み込みエラー"
CLOSE #1
EXIT SUB
END WHEN
FOR I=1 TO 12
CHARACTER INPUT #1:A$(I)
NEXT I
IF A$(1)&A$(2)&A$(3)&A$(4)<>"RIFF" THEN
PRINT "WAVファイルではありません"
CLOSE #1
EXIT SUB
END IF
LET WAVEFILESIZE=INT32(A$(5)&A$(6)&A$(7)&A$(8))
IF A$(9)&A$(10)&A$(11)&A$(12)<>"WAVE" THEN
PRINT "WAVファイルではありません"
CLOSE #1
EXIT SUB
END IF
DO
SET #1:IF MISSING THEN EXIT DO
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
SELECT CASE A$(1)&A$(2)&A$(3)&A$(4)
CASE "fmt "
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET HEADERSIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
FOR I=1 TO HEADERSIZE
CHARACTER INPUT #1:A$(I)
NEXT I
IF HEADERSIZE=16 OR HEADERSIZE=18 THEN
PRINT "標準フォーマット"
LET WAVETYPE=INT16(A$(1)&A$(2))
LET CHANNEL=INT16(A$(3)&A$(4))
LET SAMPLINGFREQ=INT32(A$(5)&A$(6)&A$(7)&A$(8))
LET DATARATE=INT32(A$(9)&A$(10)&A$(11)&A$(12))
LET SAMPLESIZE=INT16(A$(13)&A$(14))
LET SAMPLEBIT=INT16(A$(15)&A$(16))
IF HEADERSIZE=18 THEN LET CBSIZE=INT16(A$(17)&A$(18))
ELSEIF HEADERSIZE=40 THEN
PRINT "拡張フォーマット"
LET TMP=INT16(A$(1)&A$(2))
LET CHANNEL=INT16(A$(3)&A$(4))
LET SAMPLINGFREQ=INT32(A$(5)&A$(6)&A$(7)&A$(8))
LET COMPRESS=INT32(A$(9)&A$(10)&A$(11)&A$(12))
LET SAMPLESIZE=INT16(A$(13)&A$(14))
LET SAMPLEBIT=INT16(A$(15)&A$(16))
LET CBSIZE=INT16(A$(17)&A$(18))
LET BITPERSAMPLE=INT16(A$(19)&A$(20))
LET CHANNELMASK=INT32(A$(21)&A$(22)&A$(23)&A$(24))
LET FRONT_LEFT=1
LET FRONT_RIGHT=2
LET FRONT_CENTER=4
LET LOW_FREQUENCY=8
LET BACK_LEFT=16
LET BACK_RIGHT=32
LET FRONT_LEFT_OF_CENTER=64
LET FRONT_RIGHT_OF_CENTER=128
LET BACK_CENTER=256
LET SIDE_LEFT=512
LET SIDE_RIGHT=1024
LET TOP_CENTER=2048
LET TOP_FRONT_LEFT=4096
LET TOP_FRONT_CENTER=8192
LET TOP_FRONT_RIGHT=16384
LET TOP_BACK_LEFT=32768
LET TOP_BACK_CENTER=65536
LET TOP_BACK_RIGHT=131072
LET ALL=2147483648
END IF
CASE "data"
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET PCMSIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
! FOR I=1 TO PCMSIZE
! CHARACTER INPUT #1:DMY$
! NEXT I
EXIT DO
CASE "fact"
FOR I=1 TO 8
CHARACTER INPUT #1:A$(I)
NEXT I
LET SIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
IF MOD(SIZE,2)=1 THEN LET SIZE=SIZE+1
!'LET PCMSIZE=INT32(A$(5)&A$(6)&A$(7)&A$(8))
CASE "LIST"
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
!'LET LISTSIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
SELECT CASE A$(1)&A$(2)&A$(3)&A$(4)
CASE "INFO"
SET #1:IF MISSING THEN EXIT DO
FOR I=1 TO 8
CHARACTER INPUT #1:A$(I)
NEXT I
LET SIZE=INT32(A$(5)&A$(6)&A$(7)&A$(8))
IF MOD(SIZE,2)=1 THEN LET SIZE=SIZE+1
SELECT CASE A$(1)&A$(2)&A$(3)&A$(4)
CASE "IART"
PRINT "アーティスト"
CASE "ICMS"
PRINT "コミッション"
CASE "ICMT"
PRINT "コメント"
CASE "ICOP"
PRINT "著作権"
CASE "ICRD"
PRINT "作成日"
CASE "INAM"
PRINT "名前"
CASE "IPRD"
PRINT "製品名"
CASE "IGNR"
PRINT "ジャンル"
CASE "IENG"
PRINT "エンジニア名"
CASE "ISRC"
PRINT "オリジナル作成者"
CASE "ISFT"
PRINT "使用したソフト"
CASE "IKEY"
PRINT "キーワード"
CASE "ITCH"
PRINT "技術者名"
CASE "ISBJ"
PRINT "タイトル"
CASE ELSE
PRINT A$(1)&A$(2)&A$(3)&A$(4)
END SELECT
FOR I=1 TO SIZE
CHARACTER INPUT #1:D$
PRINT D$;
NEXT I
PRINT
CASE "adtl"
DO
SET #1:IF MISSING THEN EXIT DO
FOR I=1 TO 8
CHARACTER INPUT #1:A$(I)
NEXT I
LET SIZE=INT32(A$(5)&A$(6)&A$(7)&A$(8))
IF MOD(SIZE,2)=1 THEN LET SIZE=SIZE+1
SELECT CASE A$(1)&A$(2)&A$(3)&A$(4)
CASE "label"
PRINT"LABEL"
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
PRINT INT32(A$(1)&A$(2)&A$(3)&A$(4))
CASE "note"
PRINT "NOTE"
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
PRINT INT32(A$(1)&A$(2)&A$(3)&A$(4))
CASE "ltxt"
PRINT "LABELED TEXT"
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
PRINT INT32(A$(1)&A$(2)&A$(3)&A$(4))
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
PRINT INT32(A$(1)&A$(2)&A$(3)&A$(4))
CASE "file"
PRINT "EMBEDDID FILE"
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
PRINT INT32(A$(1)&A$(2)&A$(3)&A$(4))
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
PRINT INT32(A$(1)&A$(2)&A$(3)&A$(4))
END SELECT
DO
CHARACTER INPUT #1:D$
IF D$=CHR$(0) THEN EXIT DO
PRINT D$;
LOOP
PRINT
LOOP
END SELECT
CASE "cue "
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET CUEPOINT=INT32(A$(1)&A$(2)&A$(3)&A$(4))
PRINT "CUEPOINT=";CUEPOINT
FOR J=1 TO CUEPOINT
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET DWLDENTIFIER=INT32(A$(1)&A$(2)&A$(3)&A$(4))
PRINT "DWLDENTIFIER=";DWLDENTIFIER
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET POSITION=INT32(A$(1)&A$(2)&A$(3)&A$(4))
PRINT "POSITION=";POSITION
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
PRINT A$(1);A$(2);A$(3);A$(4)
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET CHUNKSTART=INT32(A$(1)&A$(2)&A$(3)&A$(4))
PRINT "CHUNKSTART=";CHUNKSTART
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET BLOCKSTART=INT32(A$(1)&A$(2)&A$(3)&A$(4))
PRINT "BLOCK START=";BLOCKSTART
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET SAMPLEOFFSET=INT32(A$(1)&A$(2)&A$(3)&A$(4))
PRINT "SAMPLEOFFSET=";SAMPLEOFFSET
NEXT J
CASE "DISP"
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET TYPE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
IF TYPE=1 THEN
DO
CHARACTER INPUT #1:D$
IF D$=CHR$(0) THEN EXIT DO
PRINT D$;
LOOP
PRINT
ELSE
PRINT "TYPE";TYPE
END IF
CASE "plst"
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET SEGMENT=INT32(A$(1)&A$(2)&A$(3)&A$(4))
PRINT "SEGMENT=";SEGMENT
FOR J=1 TO SEGMENT
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET DWLDENTIFIER=INT32(A$(1)&A$(2)&A$(3)&A$(4))
PRINT "DWLDENTIFIER=";DWLDENTIFIER
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET SAMPLE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
PRINT "SAMPLE=";SAMPLE
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET REPEATS=INT32(A$(1)&A$(2)&A$(3)&A$(4))
PRINT "REPEAT=";REPEATS
NEXT J
CASE "PEAK"
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET SIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
FOR I=1 TO SIZE
CHARACTER INPUT #1:DMY$
NEXT I
CASE "JUNK"
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET SIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
FOR I=1 TO SIZE
CHARACTER INPUT #1:DMY$
NEXT I
CASE ELSE
PRINT "未対応チャンク:";A$(1)&A$(2)&A$(3)&A$(4)
FOR I=1 TO 4
CHARACTER INPUT #1:A$(I)
NEXT I
LET SIZE=INT32(A$(1)&A$(2)&A$(3)&A$(4))
FOR I=1 TO SIZE
CHARACTER INPUT #1:DMY$
! PRINT BSTR$(ORD(DMY$),16);" ";
NEXT I
PRINT
END SELECT
LOOP
CLOSE #1
PRINT "ファイルサイズ ";WAVEFILESIZE
IF HEADERSIZE=16 OR HEADERSIZE=18 THEN
LET SECOND=PCMSIZE/DATARATE
SELECT CASE WAVETYPE
CASE 0
PRINT "Unknown"
CASE 1
PRINT "PCM"
CASE 2
PRINT "MS ADPCM"
CASE 3
PRINT "IEEE754 浮動小数"
CASE 5
PRINT "IBM CSVD"
CASE 6
PRINT "G711 A-Law"
CASE 7
PRINT "G711 μ-Law"
CASE 16
PRINT "OKI ADPCM"
CASE 17
PRINT "IMA-ADPCM"
CASE 18
PRINT "MediaSpace ADPCM"
CASE 19
PRINT "Sierra ADPCM"
CASE 20
PRINT "G723 ADPCM"
END SELECT
END IF
PRINT "チャンネル数 ";CHANNEL
PRINT "サンプリング周波数 ";SAMPLINGFREQ;"Hz"
PRINT "データレート ";DATARATE
PRINT "ブロックサイズ ";SAMPLESIZE
PRINT "サンプリングビット ";SAMPLEBIT;"bit"
PRINT "PCMサイズ ";PCMSIZE
PRINT "データ数 ";PCMSIZE/SAMPLESIZE
IF SECOND>0 THEN PRINT "時間 ";SECOND;"秒"
IF HEADERSIZE=40 THEN
PRINT "チャンネルマスク ";
IF BITAND(CHANNELMASK,FRONT_LEFT)>0 THEN PRINT "前面 左チャンネル ";
IF BITAND(CHANNELMASK,FRONT_RIGHT)>0 THEN PRINT "前面 右チャンネル ";
IF BITAND(CHANNELMASK,FRONT_CENTER)>0 THEN PRINT "前面 中央チャンネル ";
IF BITAND(CHANNELMASK,LOW_FREQUENCY)>0 THEN PRINT "低周波用 ";
IF BITAND(CHANNELMASK,BACK_LEFT)>0 THEN PRINT "後面 左チャンネル ";
IF BITAND(CHANNELMASK,BACK_RIGHT)>0 THEN PRINT "後面 右チャンネル ";
IF BITAND(CHANNELMASK,FRONT_LEFT_OF_CENTER)>0 THEN PRINT "前面 中央左チャンネル ";
IF BITAND(CHANNEL,FRONT_RIGHT_OF_CENTER)>0 THEN PRINT "前面 中央右チャンネル ";
IF BITAND(CHANNEL,BACK_CENTER)>0 THEN PRINT "後面 中央チャンネル ";
IF BITAND(CHANNEL,SIDE_LEFT)>0 THEN PRINT "側面 左チャンネル ";
IF BITAND(CHANNEL,SIDE_RIGHT)>0 THEN PRINT "側面 右チャンネル ";
IF BITAND(CHANNEL,TOP_CENTER)>0 THEN PRINT "上方 中央チャンネル ";
IF BITAND(CHANNEL,TOP_FRONT_LEFT)>0 THEN PRINT "上方前面 左チャンネル ";
IF BITAND(CHANNEL,TOP_FRONT_CENTER)>0 THEN PRINT "上方前面 中央チャンネル ";
IF BITAND(CHANNEL,TOP_FRONT_RIGHT)>0 THEN PRINT "上方前面 右チャンネル ";
IF BITAND(CHANNEL,TOP_BACK_LEFT)>0 THEN PRINT "上方後面 左チャンネル ";
IF BITAND(CHANNEL,TOP_BACK_CENTER)>0 THEN PRINT "上方後面 中央チャンネル ";
IF BITAND(CHANNEL,TOP_BACK_RIGHT)>0 THEN PRINT "上方後面 右チャンネル ";
IF BITAND(CHANNEL,ALL)>0 THEN PRINT "全チャンネル ";
PRINT
PRINT "圧縮データレート ";COMPRESS
END IF
END SUB
以下略
Re: wavファイル読み込みルーチン - しばっち
2024/10/13 (Sun) 07:29:47
C/C++によるWAVファイル読み込みルーチンです。32bit版のみです。
VC++2022でコンパイルしました。
下記c/cppソースからVC++2022でコンパイルできます。
EXTERNAL SUB READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN(),RIN(),ERR)
OPTION CHARACTER BYTE
LET ERR=0
WHEN EXCEPTION IN
OPEN #1:NAME F$
ASK #1: FILESIZE SIZE
CLOSE #1
USE
LET ERR=2
EXIT SUB
END WHEN
IF SIZE=0 THEN
LET ERR=2
EXIT SUB
END IF
LET GETDATA$=REPEAT$(CHR$(0),SIZE+1)
LET K=GETBINARY(F$,0,SIZE,GETDATA$)
IF K<>0 THEN
LET ERR=1
! PRINT "読み込みエラー"
EXIT SUB
END IF
IF GETDATA$(1:4)<>"RIFF" THEN
LET ERR=1
!PRINT "WAVファイルではありません"
EXIT SUB
END IF
LET WAVEFILESIZE=INT32(GETDATA$(5:8))
IF GETDATA$(9:12)<>"WAVE" THEN
LET ERR=1
!PRINT "WAVファイルではありません"
EXIT SUB
END IF
LET SEEK=12
DO
LET SEEK=SEEK+4
SELECT CASE GETDATA$(SEEK-3:SEEK)
CASE "fmt "
LET HEADERSIZE=INT32(GETDATA$(SEEK+1:SEEK+4))
LET SEEK=SEEK+4
LET WAVETYPE=INT16(GETDATA$(SEEK+1:SEEK+2))
IF WAVETYPE<>1 THEN
LET ERR=1
!PRINT "対応していません"
EXIT SUB
END IF
LET CHANNEL=INT16(GETDATA$(SEEK+3:SEEK+4))
LET SAMPLINGFREQ=INT32(GETDATA$(SEEK+5:SEEK+8))
LET DATARATE=INT32(GETDATA$(SEEK+9:SEEK+12))
LET SAMPLESIZE=INT16(GETDATA$(SEEK+13:SEEK+14))
LET SAMPLEBIT=INT16(GETDATA$(SEEK+15:SEEK+16))
LET SEEK=SEEK+HEADERSIZE
CASE "data"
LET PCMSIZE=INT32(GETDATA$(SEEK+1:SEEK+4))
!LET SECOND=PCMSIZE/DATARATE
LET NUM=PCMSIZE/SAMPLESIZE
LET SEEK=SEEK+4
EXIT DO
CASE "fact"
!'LET SIZE=INT32(GETDATA$(SEEK+1:SEEK+4)
!'LET PCMSIZE=INT32(GETDATA$(SEEK+5:SEEK+7))
LET SEEK=SEEK+8
CASE "LIST"
LET LISTSIZE=INT32(GETDATA$(SEEK+1:SEEK+4))
LET SEEK=SEEK+4+LISTSIZE
CASE ELSE
! PRINT "対応していません"
LET ERR=1
EXIT SUB
END SELECT
LOOP
!REDIM LIN(NUM)
!REDIM RIN(NUM)
LET A=INT(NUM/100)
PRINT "読み込み中"
FOR K=1 TO NUM
IF MOD(K,INT(NUM/A))=0 AND INT(K/A)<>R THEN
LET R=INT(K/A)
PRINT R;"%"
END IF
FOR CH=1 TO CHANNEL
SELECT CASE SAMPLEBIT
CASE 8
LET B$=GETDATA$(SEEK:SEEK)
LET SEEK=SEEK+1
LET DAT=(ORD(B$)-128)/2^7
CASE 16
LET B$=GETDATA$(SEEK:SEEK+1)
LET SEEK=SEEK+2
LET DAT=INT16(B$)/2^15
CASE 24
LET B$=GETDATA$(SEEK:SEEK+2)
LET SEEK=SEEK+3
LET DAT=INT24(B$)/2^23
CASE 32
LET B$=GETDATA$(SEEK:SEEK+4)
LET SEEK=SEEK+3
LET DAT=INT24(B$)/2^31
CASE 64
LET B$=GETDATA$(SEEK:SEEK+8)
LET SEEK=SEEK+3
LET DAT=INT64(B$)/2^63
END SELECT
SELECT CASE CH
CASE 1
LET LIN(K)=DAT
CASE 2
LET RIN(K)=DAT
CASE ELSE
END SELECT
NEXT CH
NEXT K
END SUB
EXTERNAL FUNCTION GETBINARY(NAME$,SEEK,SIZE,DA$)
ASSIGN ".\DLL\fileread.dll","fileread"
END FUNCTION
EXTERNAL FUNCTION GETBINARY2(NAME$,SEEK,SIZE,DA$)
ASSIGN ".\DLL\fileread2.dll","fileread"
END FUNCTION
以下略
---------------------------------------------------------------------------
fileread.c
#include <stdio.h>
__declspec(dllexport) int fileread(char *name,int offset,int size,char *data)
{
FILE *fp;
int l;
if ((fp = fopen(name, "rb")) == NULL) {
return 1;
}
fseek(fp,offset,SEEK_SET);
l=fread(data,size,1,fp);
if(l<1) return 2;
fclose(fp);
return 0;
}
__declspec(dllexport) int filewrite(char *name,int offset,int size,char *data)
{
FILE *fp;
int l;
if ((fp = fopen(name, "wb")) == NULL) {
return 1;
}
fseek(fp,offset,SEEK_SET);
l=fwrite(data,size,1,fp);
if (l<1) return 2;
fclose(fp);
return 0;
}
---------------------------------------------------------------------------
fileread2.cpp
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
using namespace std;
extern "C" __declspec(dllexport) int fileread(char *name,int seek,int size,char *data)
{
ifstream iFstrm(name, ios::in | ios::binary);
if (iFstrm.fail()) return 1;
iFstrm.seekg(seek);
iFstrm.read(data,size);
iFstrm.close();
return 0;
}
extern "C" __declspec(dllexport) int filewrite(char *name,int seek,int size,char *data)
{
ofstream oFstrm(name, ios::in | ios::binary);
if (oFstrm.fail()) return 1;
oFstrm.seekp(seek);
oFstrm.write(data,size);
oFstrm.close();
return 0;
}
Re: wavファイル読み込みルーチン - しばっち
2024/10/13 (Sun) 07:30:52
C/C++ライブラリーによるREADWAVのdll版です。32bit版のみです。
https://github.com/adamstark/AudioFile
ヘッダーライブラリーです。ヘッダーファイルをインクルードするだけで使えます。
上記URLからzipファイルをダウンロードしてVC++2022で下記cppソースからコンパイルできます。
-1~1の正規値を返します。
このサブルーチンの仕様はREADWAVと同じです。置き換えできます。
ERR=999の時はバッファー不足です。
PCMデータは途中までしか読み出されていません。
ERRはdll内でのエラー箇所を特定するためのコードです。
VC++2022でコンパイルしました。
下記からダウンロードしてください。(wave.zip)29.9 MB (31,410,628 バイト)
https://66.gigafile.nu/0121-d5d86eb73a1f6ce256c440f69c9462329
ダウンロード期限:2025年1月21日(火)
パスワード:設定していません
EXTERNAL SUB READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN(),RIN(),ERR)
OPTION CHARACTER BYTE
IF F$="" THEN EXIT SUB
IF POS(LCASE$(F$),".wav")=0 AND POS(LACSE$(F$),".aiff")=0 THEN LET F$=F$&".wav"
LET NUM$=REPEAT$(" ",4)
LET SAMPLINGFREQ$=REPEAT$(" ",4)
LET CHANNEL$=REPEAT$(" ",4)
LET SAMPLEBIT$=REPEAT$(" ",4)
IF NUM=0 THEN LET NUM=UBOUND(LIN,1)
LET L$=REPEAT$(" ",8*NUM)
LET R$=REPEAT$(" ",8*NUM)
LET NUM$(1:4)=DWORD$(NUM) ! バッファーサイズ設定
LET ERR=READWAV_(F$,NUM$,CHANNEL$,SAMPLINGFREQ$,L$,R$)
IF ERR=1 THEN EXIT SUB
LET NUM=INT32(NUM$(1:4))
LET SAMPLINGFREQ=INT32(SAMPLINGFREQ$(1:4))
LET CHANNEL=INT32(CHANNEL$(1:4))
LET SAMPLEBIT=INT32(SAMPLEBIT$(1:4))
FOR I=0 TO NUM-1
LET LIN(I+1)=UNPACKDBL(L$(8*I+1:8*I+8))
IF CHANNEL=2 THEN LET RIN(I+1)=UNPACKDBL(R$(8*I+1:8*I+8))
NEXT I
FUNCTION READWAV_(F$,NUM$,CHANNEL$,SAMPLINGFREQ$,SAMPLEBIT$,L$,R$)
OPTION CHARACTER BYTE
ASSIGN ".\DLL\readwav.dll","readwav"
END FUNCTION
END SUB
EXTERNAL FUNCTION INT32(A$)
OPTION CHARACTER BYTE
DECLARE NUMERIC A
LET A$=LEFT$(A$,4)
LET A=ORD(A$(1:1))+ORD(A$(2:2))*256+ORD(A$(3:3))*256^2+ORD(A$(4:4))*256^3
IF A>=2^31-1 THEN LET A=A-2^32
LET INT32=A
END FUNCTION
--------------------------------------------------------------------------------
readwav.cpp
#include "AudioFile.h"
using namespace std;
extern "C" __declspec(dllexport) int readwav(char *name,int *num,int *channel,int *samplingfreq,int *samplebit,double *lin,double *rin)
{
AudioFile<double> audioFile;
int err=0;
if(!audioFile.load(name)) return 1;
*samplingfreq = audioFile.getSampleRate();
*samplebit = audioFile.getBitDepth();
int numsample = audioFile.getNumSamplesPerChannel();
*channel = audioFile.getNumChannels();
if (numsample>*num)
err=999; // バッファー不足
else
*num=numsample;
for (int i = 0; i < *num; i++)
{
lin[i] = audioFile.samples[0][i];
if(*channel==2) rin[i] = audioFile.samples[1][i];
}
return err;
}
--------------------------------------------------------------------------------
使用例
LET NUM=44100*200
DIM LIN(NUM),RIN(NUM)
FILE GETOPENNAME F$,"読み込み WAV,AIFFファイル|*.WAV;*.AIFF"
IF F$="" THEN STOP
CALL READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN,ERR)
IF ERR>0 THEN STOP
以下略
Re: wavファイル読み込みルーチン - しばっち
2024/10/13 (Sun) 07:32:00
C/C++ライブラリーによるREADWAVのdll版です。32bit版のみです。
https://github.com/audionamix/wave
-1~1の正規値を返します。
このサブルーチンの仕様はREADWAVと同じです。置き換えできます。
ERR=999の時はバッファー不足です。
PCMデータは途中までしか読み出されていません。
ERRはdll内でのエラー箇所を特定するためのコードです。
このプログラムではfloat型を使用していますが精度的には問題ないかと思います。(double型に未対応のため)
VC++2022でコンパイルしました。
EXTERNAL SUB READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN(),RIN(),ERR)
OPTION CHARACTER BYTE
IF F$="" THEN EXIT SUB
IF POS(LCASE$(F$),".wav")=0 THEN LET F$=F$&".wav"
LET NUM$=REPEAT$(" ",4)
LET SAMPLINGFREQ$=REPEAT$(" ",4)
LET CHANNEL$=REPEAT$(" ",4)
LET SAMPLEBIT$=REPEAT$(" ",4)
IF NUM=0 THEN LET NUM=UBOUND(LIN,1)
LET L$=REPEAT$(" ",8*NUM)
LET R$=REPEAT$(" ",8*NUM)
LET NUM$(1:4)=DWORD$(NUM) ! バッファーサイズ設定
LET ERR=READWAV_(F$,NUM$,CHANNEL$,SAMPLINGFREQ$,SAMPLEBIT$,L$,R$)
IF ERR=1 THEN EXIT SUB
LET NUM=INT32(NUM$(1:4))
LET SAMPLINGFREQ=INT32(SAMPLINGFREQ$(1:4))
LET CHANNEL=INT32(CHANNEL$(1:4))
LET SAMPLEBIT=INT32(SAMPLEBIT$(1:4))
FOR I=0 TO NUM-1
LET LIN(I+1)=UNPACKDBL(L$(8*I+1:8*I+8))
IF CHANNEL=2 THEN LET RIN(I+1)=UNPACKDBL(R$(8*I+1:8*I+8))
NEXT I
FUNCTION READWAV_(F$,NUM$,CHANNEL$,SAMPLINGFREQ$,SAMPLEBIT$,L$,R$)
OPTION CHARACTER BYTE
ASSIGN ".\DLL\readwave.dll","readwav"
END FUNCTION
END SUB
以下略
--------------------------------------------------------------------------------
readwave.cpp
#include "wave/file.h"
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
using namespace wave;
extern "C" __declspec(dllexport) int readwav(char *name,int *num,int *channel,int *samplingfreq,int *samplebit,double *lin,double *rin)
{
int ch,i,n,k=0,er=0;
File read_file;
Error err=read_file.Open(name,kIn);
if(err) return 1;
vector<float> content;
err=read_file.Read(&content);
if(err) return 2;
*samplingfreq=read_file.sample_rate(); // サンプリング周波数
*channel=read_file.channel_number(); // チャンネル数
*samplebit=read_file.bits_per_sample(); // サンプルビット
n=content.size()/read_file.channel_number(); // データ数
if(n>*num) er=999; // バッファー不足
else *num=n;
for(i=0; i<content.size(); i+=read_file.channel_number()) {
for (ch=0; ch<*channel; ch++) {
if(ch==0) lin[k]=(double)content[i+ch];
if(ch==1) rin[k]=(double)content[i+ch];
}
k++;
if (k>=*num) break;
}
return er;
}
Re: wavファイル読み込みルーチン - しばっち
2024/10/13 (Sun) 07:33:18
C/C++ライブラリーによるREADWAVのdll版です。32bit版のみです。
https://github.com/DIYFXWorld/Other
https://github.com/Numerix-DSP/wav_file
ヘッダーライブラリーです。ヘッダーファイルをインクルードするだけで使えます。
上記URLからダウンロードしてVC++2022で下記cppソースからコンパイルできます。
このサブルーチンの仕様はREADWAVと同じです。置き換えできます。
ERR=999の時はバッファー不足です。
PCMデータは途中までしか読み出されていません。
VC++2022でコンパイルしました。
EXTERNAL SUB READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN(),RIN(),ERR)
OPTION CHARACTER BYTE
IF F$="" THEN EXIT SUB
LET NUM$=REPEAT$(" ",4)
LET SAMPLINGFREQ$=REPEAT$(" ",4)
LET CHANNEL$=REPEAT$(" ",4)
LET SAMPLEBIT$=REPEAT$(" ",4)
IF NUM=0 THEN LET NUM=UBOUND(LIN,1)
LET LIN$=REPEAT$(" ",8*NUM)
LET RIN$=REPEAT$(" ",8*NUM)
LET NUM$(1:4)=DWORD$(NUM) ! バッファーサイズ設定
LET ERR=READWAV_(F$,NUM$,CHANNEL$,SAMPLINGFREQ$,SAMPLEBIT$,LIN$,RIN$)
IF ERR>0 THEN EXIT SUB
LET SAMPLINGFREQ=INT32(SAMPLINGFREQ$(1:4))
LET CHANNEL=INT32(CHANNEL$(1:4))
LET SAMPLEBIT=INT32(SAMPLEBIT$(1:4))
LET NUM=INT32(NUM$(1:4))
FOR I=0 TO NUM-1
LET LIN(I+1)=UNPACKDBL(LIN$(8*I+1:8*I+8))
IF CHANNEL=2 THEN LET RIN(I+1)=UNPACKDBL(RIN$(8*I+1:8*I+8))
NEXT I
FUNCTION READWAV_(F$,NUM$,CHANNEL$,SAMPLINGFREQ$,SAMPLEBIT$,LIN$,RIN$)
OPTION CHARACTER BYTE
ASSIGN ".\DLL\readwave2.dll","readwav"
END FUNCTION
END SUB
!FUNCTION READWAV_(F$,NUM$,CHANNEL$,SAMPLINGFREQ$,SAMPLEBIT$,LIN$,RIN$)
! OPTION CHARACTER BYTE
! ASSIGN ".\DLL\readwave3.dll","readwav"
!END FUNCTION
END SUB
以下略
--------------------------------------------------------------------------------
readwave2.cpp
#include "wave.hpp"
using namespace std;
extern "C" __declspec(dllexport) int readwav(char *name,int *num,int *channel,int *samplingfreq,int *samplebit,double *lin,double *rin)
{
int i,n,err=0;
wave<double> src;
wav_info wi=get_wav_info(name);
load(name,src);
n=wi.length;
*channel=wi.channel;
*samplingfreq=wi.fs;
*samplebit=wi.bits;
if (n>*num) err=999; // バッファー不足
else *num=n;
for(i=0; i<*num; i++) {
if(*channel==1) lin[i]=src[i];
if(*channel==2) {
lin[i]=src.L[i];
rin[i]=src.R[i];
}
}
return err;
}
--------------------------------------------------------------------------------
readwave3.c
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "wav_file.h"
#include <math.h>
__declspec(dllexport) int readwav(char *name,int *num,int *channel,int *samplingfreq,int *samplebit,double *lin,double *rin)
{
FILE *fpwav,*fpcsv;
int count,n=0,no,err=0;
WAV_FILE_INFO wavinfo;
double *dat;
if ((fpwav=fopen(name,"rb"))==NULL) return 3;
wavinfo=wav_read_header(fpwav);
if (wavinfo.NumberOfChannels == 0) return 2;
no=wavinfo.NumberOfSamples;
if(no>*num* *channel) err=999; // バッファー不足
else *num=no;
dat=(double *)malloc(sizeof(double)* *num);
*channel=wavinfo.NumberOfChannels;
*samplingfreq=wavinfo.SampleRate;
*samplebit=wavinfo.WordLength;
while ((count = (int)wav_read_data (dat, fpwav, wavinfo, *num)) == *num) {
for (int i = 0; i < count/ *channel; i++) {
for(int ch=0; ch<*channel; ch++) {
if (ch==0) lin[n]=dat[i* *channel+ch]/pow(2.0,*samplebit-1);
if (ch==1) rin[n]=dat[i* *channel+ch]/pow(2.0,*samplebit-1);
}
n++;
}
}
*num=*num/ *channel;
fclose(fpwav);
free(dat);
return err;
}
Re: wavファイル読み込みルーチン - しばっち
2024/10/13 (Sun) 07:34:42
C/C++ライブラリーによるREADWAVのdll版です。32bit版のみです。
http://www.mega-nerd.com/libsndfile/
このサブルーチンの仕様はREADWAVと同じです。置き換えできます。
ERR=999の時はバッファー不足です。
途中までしか読み出しされていません。
ERRはdll内でのエラー箇所を特定するためのコードです。
VC++2022でコンパイルしました。
EXTERNAL SUB READSND(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN(),RIN(),ERR)
OPTION CHARACTER BYTE
IF F$="" THEN EXIT SUB
LET NUM$=REPEAT$(" ",4)
LET SAMPLINGFREQ$=REPEAT$(" ",4)
LET CHANNEL$=REPEAT$(" ",4)
LET SAMPLEBIT$=REPEAT$(" ",4)
IF NUM=0 THEN LET NUM=UBOUND(LIN,1)
LET DAT$=REPEAT$(" ",8*NUM*2) ! 8byte*NUM個*2ch
LET NUM$(1:4)=DWORD$(NUM*2) ! 2ch分
LET ERR=READSND_(F$,NUM$,CHANNEL$,SAMPLINGFREQ$,SAMPLEBIT$,DAT$)
IF ERR>1 THEN EXIT SUB
LET SAMPLINGFREQ=INT32(SAMPLINGFREQ$(1:4))
LET CHANNEL=INT32(CHANNEL$(1:4))
LET NUM=INT32(NUM$(1:4))
LET SAMPLEBIT=INT32(SAMPLEBIT$(1:4))
FOR I=0 TO NUM-1
IF CHANNEL=1 THEN
LET LIN(I+1)=UNPACKDBL(DAT$(8*I+1:8*I+8))
END IF
IF CHANNEL=2 THEN
LET LIN(I+1)=UNPACKDBL(DAT$(16*I+1:16*I+8))
LET RIN(I+1)=UNPACKDBL(DAT$(16*I+9:16*I+16))
END IF
NEXT I
FUNCTION READSND_(F$,NUM$,CHANNEL$,SAMPLINGFREQ$,SAMPLEBIT$,DAT$)
OPTION CHARACTER BYTE
ASSIGN ".\DLL\readsnd.dll","readwav"
END FUNCTION
END SUB
以下略
--------------------------------------------------------------------------------
readsnd.c
#include "sndfile.h"
#include <stdio.h>
#include <stdlib.h>
#define BLOCK_SIZE 4096
__declspec(dllexport) int readwav(char *filename,int *num,int *channel,int *samplingfreq,int *samplebit,double *data)
{
SNDFILE *sfr;
SF_INFO sfinfo;
int i,n=0,err=0,count,readcount,frames,ch;
double *dat;
memset (&sfinfo, 0, sizeof (sfinfo));
if(!(sfr = sf_open(filename, SFM_READ, &sfinfo))) return 2;
*samplingfreq=sfinfo.samplerate;
count=sfinfo.frames;
*channel=sfinfo.channels;
frames=BLOCK_SIZE/ *channel;
if(sfinfo.format==SF_FORMAT_PCM_S8) *samplebit=8;
if(sfinfo.format==SF_FORMAT_PCM_16) *samplebit=16;
if(sfinfo.format==SF_FORMAT_PCM_24) *samplebit=24;
if(sfinfo.format==SF_FORMAT_PCM_32) *samplebit=32;
if(sfinfo.format==SF_FORMAT_FLOAT) *samplebit=32;
if(sfinfo.format==SF_FORMAT_DOUBLE) *samplebit=64;
if(sfinfo.format==SF_FORMAT_ULAW) *samplebit=8;
if(sfinfo.format==SF_FORMAT_ALAW) *samplebit=8;
dat=(double *)malloc(BLOCK_SIZE*sizeof(double));
if(dat==NULL) return 1;
if(count>*num) err=999; // バッファー不足
else *num=count;
while((readcount=(int)sf_read_double(sfr,dat,frames))>0)
{
for(i=0; i<readcount; i++) {
for(ch=0; ch<*channel; ch++) {
data[n++]=dat[i* *channel+ch];
if(n>*num) goto jump;
}
}
}
jump:
sf_close(sfr);
free(dat);
return err;
}
--------------------------------------------------------------------------------
READSNDルーチン使用例
LET NUM=44100*200
DIM LIN(NUM),RIN(NUM)
FILE GETOPENNAME F$,"読み込み ファイル|*.wav;*.aiff;*.aifc;*.au;*.snd;*.raw;*.paf;*.iff;*.svx;*.sf;*.voc;*.w64;*.mat4;*.mat5;*.pvf;*.xi;*.htk;*.caf;*.sd2;*.flac;*.ogg"
IF F$="" THEN STOP
CALL READWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LIN,RIN,ERR)
IF ERR>1 THEN STOP
以下略
Re: wavファイル読み込みルーチン - しばっち
2024/10/13 (Sun) 07:36:09
C/C++ライブラリーによるREADWAVのdll版です。32bit版のみです。
https://github.com/adamstark/AudioFile
ヘッダーライブラリーです。ヘッダーファイルをインクルードするだけで使えます。
上記URLからダウンロードしてVC++2022で下記cppソースからコンパイルできます。
-1~1の正規値を返します。
マルチチャンネル読み込み対応のため一部仕様を変更しています。
拡張フォーマットには対応していないようです。
ERR=999の時はバッファー不足です。
PCMデータは途中までしか読み出されていません。
ERRはdll内でのエラー箇所を特定するためのコードです。
VC++2022でコンパイルしました。
EXTERNAL SUB READWAVMULTI(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT(,),ERR)
OPTION CHARACTER BYTE
IF F$="" THEN EXIT SUB
IF POS(LCASE$(F$),".wav")=0 AND POS(LCASE$(F$),".aiff")=0 THEN LET F$=F$&".wav"
LET NUM$=REPEAT$(" ",4)
LET SAMPLINGFREQ$=REPEAT$(" ",4)
LET CHANNEL$=REPEAT$(" ",4)
LET SAMPLEBIT$=REPEAT$(" ",4)
IF NUM=0 THEN LET NUM=UBOUND(DAT,2)
LET DAT$=REPEAT$(" ",8*NUM*CHANNEL)
LET NUM$(1:4)=DWORD$(NUM)
LET ERR=READWAVMULTI_(F$,NUM$,CHANNEL$,SAMPLINGFREQ$,SAMPLEBIT$,DAT$)
IF ERR=1 THEN EXIT SUB
LET NUM=INT32(NUM$(1:4))
LET SAMPLINGFREQ=INT32(SAMPLINGFREQ$(1:4))
LET CHANNEL=INT32(CHANNEL$(1:4))
LET SAMPLEBIT=INT32(SAMPLEBIT$(1:4))
FOR I=0 TO NUM-1
FOR CH=0 TO CHANNEL-1
LET DAT(CH+1,I+1)=UNPACKDBL(DAT$(8*I*CHANNEL+8*CH+1:8*I*CHANNEL+8*CH+8))
NEXT CH
NEXT I
FUNCTION READWAVMULTI_(F$,NUM$,CHANNEL$,SAMPLINGFREQ$,SAMPLEBIT$,DAT$)
OPTION CHARACTER BYTE
ASSIGN ".\DLL\readwavmulti.dll","readwav"
END FUNCTION
END SUB
以下略
--------------------------------------------------------------------------------
readwavmulti.cpp
#include "AudioFile.h"
using namespace std;
extern "C" __declspec(dllexport) int readwav(char *name,int *num,int *channel,int *samplingfreq,int *samplebit,double *dat)
{
AudioFile<double> audioFile;
int err=0,i,ch;
if(!audioFile.load(name)) return 1;
*samplingfreq = audioFile.getSampleRate();
*samplebit = audioFile.getBitDepth();
int numsample = audioFile.getNumSamplesPerChannel();
*channel = audioFile.getNumChannels();
if (numsample>*num)
err=999; // バッファー不足
else
*num=numsample;
for (i = 0; i < *num; i++)
for(ch=0; ch<*channel; ch++)
dat[i* *channel+ch] = audioFile.samples[ch][i];
return err;
}
--------------------------------------------------------------------------------
使用例
LET NUM=44100*100
LET CHANNEL=2
DIM DAT(CHANNEL,NUM)
FILE GETOPENNAME F$,"読み込み WAVファイル|*.WAV"
IF F$="" THEN STOP
CALL READWAVMULTI(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT,ERR)
IF ERR>0 THEN STOP
wavファイル書き出しルーチン - しばっち
2024/10/13 (Sun) 06:47:28
wavファイル書き出しルーチン
https://decimalbasic.ninja-web.net/bbs2/1702.html
https://www.youfit.co.jp/archives/1418
https://www.geidai.ac.jp/~marui/r_program/wav_files.html
https://so-zou.jp/software/tech/file/format/wav/#format-code
サブルーチンWRITEWAVはwavファイルを書き出します。
F$は保存wavファイル名です。
NUMはサンプル数です。再生時間で指定するには、サンプリング周波数に秒数を掛けた値を与えてください。(NUM=SAMPLINGFREQ*3 再生時間3秒)
0~NUM-1ではなく、1~NUMが範囲となります。OPTION BASE 0は不要です。
チャンネル数に関係なく1~NUMを与えます。
配列LOUT(配列ROUT)には-1~1までの正規化値を与えます。
この範囲を超えるとクリッピングノイズが発生します。
SAMPLINGFREQはサンプリング周波数です。8000,160000,32000,11025,22050,44100,48000等のサウンドデバイス(wavファイルの仕様)が対応している値を入れてください。
44100か22050又は48000辺りなら大抵対応しているかと思います。88200や176400、192000というのもあるようです。
※最近のWindowsはデバイス未対応のサンプリング周波数でも勝手にサンプリング周波数変換されるようです。
https://www.cepstrum.co.jp/download/recplay/recplay.html
CHANNELはチャンネル数です。モノラルならCHANNEL=1 ステレオならCHANNEL=2としてください。3チャンネル以上は無視します。
SAMPLEBITはサンプルビット数です。8,16,24,32とありますがSAMPLEBIT=16としておけば大抵の再生ソフト等で再生できるはずです。
2進モードで実行してください。
※スピーカーのボリュームには気を付けてください。
※書き込みには少し時間がかかります。
オーディオ編集ソフト
https://www.audacityteam.org/
https://soundengine.jp/software/soundengine/
https://www-ie.meijo-u.ac.jp/labs/rj001/spLibs/spwave/index-j.html
https://www.nch.com.au/wavepad/jp/index.html
https://www.ocenaudio.com/whatis
オーディオ変換ソフト
https://www.xmedia-recode.de/en/
https://www.ffmpeg.org/download.html
https://sourceforge.net/projects/sox/
オーディオ変換サイト
https://www.convertfiles.com/convert/audio/
再生ソフト
https://www.videolan.org/vlc/index.ja.html
https://sourceforge.net/projects/mpcbe/
https://www.gigafree.net/media/MediaPlayer/mediaplayerclassic.html
https://www.smplayer.info/ja/info
その他
https://www.spek.cc/
https://ackiesound.ifdef.jp/
その他サウンドレコーダー等録音ソフトとも組み合わせれば充実した
サウンドプログラミングができるかと思います。
これはサウンドプログラミングの集大成としたサブルーチン集です。
どうぞ思う存分サウンドプログラミングをお楽しみください。
EXTERNAL SUB WRITEWAV(F$,NUM,SAMPLINGFREQ,SAMPLEBIT,LOUT()) ! モノラル版
!!EXTERNAL SUB WRITEWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT(),ROUT()) ! ステレオ版(CHANNEL=1でモノラルも指定可)
OPTION CHARACTER BYTE
IF POS(LCASE$(F$),".wav")=0 THEN LET F$=F$&".wav"
OPEN #1:NAME F$
ERASE #1
SELECT CASE SAMPLEBIT
CASE 8,16,24,32
CASE ELSE
LET SAMPLEBIT=16
END SELECT
IF NUM=0 THEN LET NUM=UBOUND(LOUT,1)
LET CHANNEL=1 ! ステレオ版では外すこと
LET HEADERSIZE=16
LET WAVETYPE=1
LET PLAYTIME=NUM/SAMPLINGFREQ
LET SAMPLESIZE=SAMPLEBIT/8*CHANNEL
LET DATARATE = SAMPLESIZE * SAMPLINGFREQ
LET PCMSIZE=INT(DATARATE*PLAYTIME)
LET WAVEFILESIZE=PCMSIZE+36
PRINT #1:"RIFF";
PRINT #1:DWORD$(WAVEFILESIZE);
PRINT #1:"WAVEfmt ";
PRINT #1:DWORD$(HEADERSIZE);
PRINT #1:WORD$(WAVETYPE);
PRINT #1:WORD$(CHANNEL);
PRINT #1:DWORD$(SAMPLINGFREQ);
PRINT #1:DWORD$(DATARATE);
PRINT #1:WORD$(SAMPLESIZE);
PRINT #1:WORD$(SAMPLEBIT);
PRINT #1:"data";
PRINT #1:DWORD$(PCMSIZE);
LET A=INT(NUM/100)
PRINT "書き出し中"
FOR K=1 TO NUM
IF MOD(K,INT(NUM/A))=0 AND INT(K/A)<>R THEN
LET R=INT(K/A)
PRINT R;"%" ! カウンター表示
END IF
FOR CH=1 TO CHANNEL
SELECT CASE CH
CASE 1
LET LOUT(K)=MIN(1,MAX(LOUT(K),-1))
SELECT CASE SAMPLEBIT
CASE 8
PRINT #1:CHR$(LOUT(K)*127+128);
CASE 16
PRINT #1:WORD$(LOUT(K)*2^15);
!CASE 24
! PRINT #1:WORD24$(LOUT(K)*2^23);
!CASE 32
! PRINT #1:DWORD$(LOUT(K)*2^31);
END SELECT
! CASE 2 ! ステレオ版では以下の注釈を外すこと
! LET ROUT(K)=MIN(1,MAX(ROUT(K),-1))
! SELECT CASE SAMPLEBIT
! CASE 8
! PRINT #1:CHR$(ROUT(K)*127+128);
! CASE 16
! PRINT #1:WORD$(ROUT(K)*2^15);
! CASE 24
! PRINT #1:WORD24$(ROUT(K)*2^23);
! CASE 32
! PRINT #1:DWORD$(ROUT(K)*2^31);
! END SELECT
CASE ELSE ! 3チャンネル以上は無視
END SELECT
NEXT CH
NEXT K
CLOSE #1
END SUB
----------------------------------------------------------------------------------
上記の高速版ですが余分にメモリーが必要です。
EXTERNAL SUB WRITEWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT(),ROUT())
OPTION CHARACTER BYTE
IF POS(LCASE$(F$),".wav")=0 THEN LET F$=F$&".wav"
OPEN #1:NAME F$
ERASE #1
SELECT CASE SAMPLEBIT
CASE 8,16,24,32
CASE ELSE
LET SAMPLEBIT=16
END SELECT
LET HEADERSIZE=16
LET WAVETYPE=1
LET PLAYTIME=NUM/SAMPLINGFREQ
LET SAMPLESIZE=SAMPLEBIT/8*CHANNEL
LET DATARATE = SAMPLESIZE * SAMPLINGFREQ
LET PCMSIZE=INT(DATARATE*PLAYTIME)
LET WAVEFILESIZE=PCMSIZE+36
PRINT #1:"RIFF";
PRINT #1:DWORD$(WAVEFILESIZE);
PRINT #1:"WAVEfmt ";
PRINT #1:DWORD$(HEADERSIZE);
PRINT #1:WORD$(WAVETYPE);
PRINT #1:WORD$(CHANNEL);
PRINT #1:DWORD$(SAMPLINGFREQ);
PRINT #1:DWORD$(DATARATE);
PRINT #1:WORD$(SAMPLESIZE);
PRINT #1:WORD$(SAMPLEBIT);
PRINT #1:"data";
PRINT #1:DWORD$(PCMSIZE);
LET DAT$=REPEAT$(CHR$(0),PCMSIZE) ! メモリー確保
FOR K=1 TO NUM
SELECT CASE CHANNEL
CASE 1
LET LOUT(K)=MIN(1,MAX(LOUT(K),-1))
SELECT CASE SAMPLEBIT
CASE 8
LET DAT$(K:K)=CHR$(LOUT(K)*127+128)
CASE 16
LET DAT$(2*K-1:2*K)=WORD$(LOUT(K)*2^15)
!CASE 24
! LET DAT$(3*K-2:3*K)=WORD24$(LOUT(K)*2^23)
!CASE 32
! LET DAT$(4*K-3:4*K)=DWORD$(LOUT(K)*2^31)
END SELECT
CASE 2
LET LOUT(K)=MIN(1,MAX(LOUT(K),-1))
LET ROUT(K)=MIN(1,MAX(ROUT(K),-1))
SELECT CASE SAMPLEBIT
CASE 8
LET DAT$(2*K-1:2*K)=CHR$(LOUT(K)*127+128)&CHR$(ROUT(K)*127+128)
CASE 16
LET DAT$(4*K-3:4*K)=WORD$(LOUT(K)*2^15)&WORD$(ROUT(K)*2^15)
!CASE 24
! LET DAT$(6*K-5:6*K)=WORD24$(LOUT(K)*2^23)&WORD24$(ROUT(K)*2^23)
!CASE 32
! LET DAT$(8*K-7:8*K)=DWORD$(LOUT(K)*2^31)&DWORD$(ROUT(K)*2^31)
END SELECT
CASE ELSE ! 3チャンネル以上は無視
END SELECT
NEXT K
PRINT #1:DAT$; ! 書き込み
CLOSE #1
END SUB
----------------------------------------------------------------------------------
WINDOWS APIによるWAVファイル書き込み
EXTERNAL SUB WRITEWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT(),ROUT())
OPTION CHARACTER BYTE
IF POS(LCASE$(F$),".wav")=0 THEN LET F$=F$&".wav"
SELECT CASE SAMPLEBIT
CASE 8,16,24,32
CASE ELSE
LET SAMPLEBIT=16
END SELECT
LET HEADERSIZE=16
LET WAVETYPE=1
LET PLAYTIME=NUM/SAMPLINGFREQ
LET SAMPLESIZE=SAMPLEBIT/8*CHANNEL
LET DATARATE = SAMPLESIZE * SAMPLINGFREQ
LET PCMSIZE=SAMPLESIZE*NUM
LET WAVEFILESIZE=PCMSIZE+36
LET HEADER$="RIFF"&DWORD$(WAVEFILESIZE)&"WAVEfmt "&DWORD$(HEADERSIZE)&WORD$(WAVETYPE)&WORD$(CHANNEL)&DWORD$(SAMPLINGFREQ)&DWORD$(DATARATE)&WORD$(SAMPLESIZE)&WORD$(SAMPLEBIT)&"data"&DWORD$(PCMSIZE)
LET DAT$=REPEAT$(" ",PCMSIZE)
FOR K=1 TO NUM
SELECT CASE CHANNEL
CASE 1
LET LOUT(K)=RANGE(LOUT(K))
SELECT CASE SAMPLEBIT
CASE 8
LET DAT$(K:K)=CHR$(LOUT(K)*127+128)
CASE 16
LET DAT$(2*K-1:2*K)=WORD$(LOUT(K)*2^15)
!CASE 24
! LET DAT$(3*K-2:3*K)=WORD24$(LOUT(K)*2^23)
CASE 32
LET DAT$(4*K-3:4*K)=DWORD$(LOUT(K)*2^31)
END SELECT
CASE 2
LET LOUT(K)=RANGE(LOUT(K))
LET ROUT(K)=RANGE(ROUT(K))
SELECT CASE SAMPLEBIT
CASE 8
LET DAT$(2*K-1:2*K)=CHR$(LOUT(K)*127+128)&CHR$(ROUT(K)*127+128)
CASE 16
LET DAT$(4*K-3:4*K)=WORD$(LOUT(K)*2^15)&WORD$(ROUT(K)*2^15)
!CASE 24
! LET DAT$(6*K-5:6*K)=WORD24$(LOUT(K)*2^23)&WORD24$(ROUT(K)*2^23)
CASE 32
LET DAT$(8*K-7:8*K)=DWORD$(LOUT(K)*2^31)&DWORD$(ROUT(K)*2^31)
END SELECT
CASE ELSE
END SELECT
NEXT K
CALL FILEWRITE(F$,LEN(HEADER$&DAT$),HEADER$&DAT$)
END SUB
EXTERNAL FUNCTION RANGE(X)
LET RANGE=MIN(1,MAX(X,-1))
!RANGE=2/(1+EXP(-X))-1
!RANGE=TANH(X)
!RANGE=ATN(X)/(PI/2)
END FUNCTION
EXTERNAL SUB FILEWRITE(NAME$,NUM,DAT$)
OPTION CHARACTER BYTE
LET GENERIC_WRITE = BVAL("40000000",16)
LET GENERIC_READ = BVAL("80000000",16)
LET FILE_SHARE_READ = 1
LET FILE_SHARE_WRITE = 2
LET FILE_ATTRIBUTE_NORMAL = BVAL("80",16)
LET CREATE_NEW = 1
LET CREATE_ALWAYS = 2
LET OPEN_EXISTING = 3
LET OPEN_ALWAYS = 4
LET TRUNCATE_EXSTING = 5
LET FILE_ATTRIBUTE_NORMAL=BVAL("80",16)
LET W$="0000" ! 4バイト確保
LET HFILE=CREATEFILE(NAME$,GENERIC_WRITE,BITOR(FILE_SHARE_READ,FILE_SHARE_WRITE),0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0)
IF HFILE<>-1 THEN
CALL WRITEFILE(HFILE,DAT$,NUM,W$,0)
CALL CLOSEHANDLE(HFILE)
END IF
FUNCTION CREATEFILE(NAME$, ACC ,SHARE, SEC, CREATE, ATTRIB, HANDLE)
ASSIGN "kernel32.dll","CreateFileA"
END FUNCTION
SUB WRITEFILE(HANDLE, S$, L, W$, OV )
ASSIGN "kernel32.dll","WriteFile"
END SUB
SUB CLOSEHANDLE(HANDLE)
ASSIGN "kernel32.dll","CloseHandle"
END SUB
END SUB
Re: wavファイル書き出しルーチン - しばっち
2024/10/13 (Sun) 06:49:23
WRITEWAVルーチン使用例
各種波形音(SIN波、方形波、三角波、のこぎり波等)
https://decimalbasic.ninja-web.net/bbs2/1701.html
※高周波音が含まれていますので
くれぐれもスピーカーのボリュームに気を付けてください。
※免責事項
もし、万が一これらのサンプルの実行によりスピーカーやイヤホン・ヘッドホン及びデバイス等の破損等不具合や身体の体調不良等が発生するような事態が
起こったとしてもそれは全てサンプルを実行したユーザーの自己責任であり、当サンプルの作成者である「しばっち」は一切の責任を負わないものとします。
この条件に同意できない場合は、これらのサンプルの実行はしないようお願いします。実行した場合は同意したものとみなします。
LET FREQ=100 ! 周波数
LET SAMPLINGFREQ=44100 ! サンプリング周波数
LET PLAYTIME=3 ! 再生時間(秒)
LET NUM=PLAYTIME*SAMPLINGFREQ ! サンプル数
DIM LOUT(NUM)
FOR I=1 TO NUM
LET LOUT(I)=F(FREQ/SAMPLINGFREQ*I)*.5
NEXT I
SET WINDOW 1,NUM/100,-1,1
DRAW GRID(NUM/1000,.2)
FOR I=1 TO NUM/100
PLOT LINES:I,LOUT(I); ! 波形描画
NEXT I
CALL WRITEWAV("波形音.wav",NUM,SAMPLINGFREQ,16,LOUT)
END
EXTERNAL FUNCTION F(X)
LET F=SINE(X)
!LET F=PULSE(X)
!LET F=SQUARE(X)
!LET F=TRIANGLE(X)
!LET F=SAW(X)
!LET F=TRAPEZOIDAL(X)
!LET F=STEPSINE(X)
!LET F=STEPWISE(X)
!LET F=WEIERSTRASS(X)
!LET F=FM(X)
!LET F=NOISE(X)
!LET F=2/(1+EXP(-SIN(2*X*PI)))-1
!LET F=TANH(SIN(X*2*PI))
!LET F=TRIANGLE(X)+SAW(X)
!LET F=-STEPSINE(X)+TRAPEZOIDAL(X)
!LET F=SAW(X)+SINE(X)
!LET F=WEIERSTRASS(X)-SQUARE(X)
!LET F=SINE(X)-SQUARE(X)
!LET F=PULSE(X)-TRIANGLE(X)
!LET F=STEPSINE(X)+SAW(X)
!LET F=SQUARE(X)-TRIANGLE(X)
!LET F=TRIANGLE(X)*NOISE(X)
!LET F=MIN(1,MAX(SAW(X)*1.7,-1))
!LET F=MIN(1,MAX(TRIANGLE(X)*1.7,-1))
!LET F=MIN(1,MAX(STEPSINE(X)*1.7,-1))
LET M=.5
LET N=2
!LET F=SGN(SIN(2*PI*X))*(1-ABS(COS(2*PI*X))^M)^N
!LET F=SGN(SIN(2*PI*X))*(1-ABS(SIN(2*PI*X))^M)^N
!LET F=SGN(SIN(2*PI*X))*ABS(SIN(2*PI*X))^M*.3 ! 円形波
END FUNCTION
EXTERNAL FUNCTION SINE(X) ! SIN波
LET SINE=SIN(2*PI*X)
END FUNCTION
EXTERNAL FUNCTION PULSE(X) ! パルス波 PULSE WAVE
IF ABS(ABS(SIN(X*2*PI))-1)<.001 THEN LET PULSE=SGN(SIN(X*2*PI)) ELSE LET PULSE=0
END FUNCTION
EXTERNAL FUNCTION SQUARE(X) ! 方形波 SQUARE WAVE
LET SQUARE=SGN(SIN(X*2*PI))
END FUNCTION
EXTERNAL FUNCTION TRIANGLE(X) ! 三角波 TRIANGLE WAVE
LET TRIANGLE=ASIN(SIN(2*PI*X))/PI*2
END FUNCTION
EXTERNAL FUNCTION SAW(X) ! のこぎり波
LET SAW=MOD(2*PI*X,2*PI)/(2*PI)*2-1
END FUNCTION
EXTERNAL FUNCTION SAW2(X) ! 逆のこぎり波
LET SAW2=1-MOD(2*PI*X,2*PI)/(2*PI)*2
END FUNCTION
EXTERNAL FUNCTION TRAPEZOIDAL(X) ! 台形波 Trapezoidal wave
LET NN=MOD(2*PI*X,PI)
IF NN>PI/2 THEN LET NN=PI-NN
LET TRAPEZOIDAL=MIN(1,MAX(-1,NN*SGN(SIN(X*2*PI))))
END FUNCTION
EXTERNAL FUNCTION STEPSINE(X)
LET STEPSINE=SIN(X*2*PI)+SIN(10*X*2*PI)/10
END FUNCTION
EXTERNAL FUNCTION STEPWISE(X) ! 階段状
LET NN=4
LET STEPWISE=INT(NN*SIN(X*2*PI))/NN
END FUNCTION
EXTERNAL FUNCTION WEIERSTRASS(X) ! ワイヤストラス
LET B=11
FOR I=0 TO 13
LET S=S+.5^(I+1)*SIN(B^I*X*2*PI)
NEXT I
LET WEIERSTRASS=S
END FUNCTION
EXTERNAL FUNCTION FM(X)
LET FREQ=2.5
LET A=2
LET R=3.5
LET FM=SIN(2*PI*FREQ*X+A*SIN(2*PI*FREQ*R*X))
END FUNCTION
EXTERNAL FUNCTION NOISE(X)
LET NOISE=FP(SIN(X*45678)*1234.5)
END FUNCTION
以下略
----------------------------------------------------------------------------------
音作り(ドラム、スネア、ハイハット)
https://qiita.com/gaziya5/items/e5d058c20bc75c72b5a2
https://qiita.com/gaziya5/items/e58f8c1fce3f3f227ca7
https://qiita.com/gaziya5/items/67ebe54f4bc02bd31bd4
https://qiita.com/gaziya5/items/0a3ef4b96a6d173f0895
https://qiita.com/gaziya5/items/27ba6dedfc3028782f2f
https://qiita.com/MachiaWorx/items/75c63dff12b4a6189a35
https://qiita.com/MachiaWorx/items/43bc7868e9fc770b52f4
https://qiita.com/MachiaWorx/items/848b529afd4290d8cfda
https://qiita.com/MachiaWorx/items/a146400fd438a411b0b2
https://github.com/FMS-Cat/20180310-glsl-music
https://raku-phys.hatenablog.com/entry/2020/04/19/002400
https://machiaworx.net/?p=471
https://machiaworx.net/?p=474
https://machiaworx.net/?p=476
https://machiaworx.net/?p=478
https://nettyukobo.com/percussion_instrument_sound_synthesis/
https://nettyukobo.com/string_sound_synthesis/
LET SAMPLINGFREQ=44100 ! サンプリング周波数
LET PLAYTIME=3 ! 再生時間
LET NUM=SAMPLINGFREQ*PLAYTIME ! サンプル数
DIM LOUT(NUM)
SET WINDOW 1,NUM,-1,1
DRAW GRID(SAMPLINGFREQ,.2)
FOR I=1 TO NUM
LET TI=I/SAMPLINGFREQ
LET LOUT(I)=LCH(TI)*.5
PLOT LINES:I,LOUT(I); ! 波形表示
NEXT I
CALL WRITEWAV("リズム.wav",NUM,SAMPLINGFREQ,16,LOUT)
END
EXTERNAL FUNCTION LCH(T)
LET CH=3*SIN(300*T)*FP(-T*2)^4
LET CH=CH+.5*SIN(40000*T)*FP(-2*T+.5)
LET CH=CH+DFM(T,0)+DFM(T,.5)+DFM(T,1)+DFM(T,2)
LET CH=CH*.3
LET LCH=CH
END FUNCTION
EXTERNAL FUNCTION DFM(T,DT)
LET DFM=EXP(-3*DT)*FM(8*T)*RHY(T-.3*DT,DT)
END FUNCTION
EXTERNAL FUNCTION RHY(T,F)
LET RHY=FP(MOD(-T*8,8)/3)^(6-3*F)
END FUNCTION
EXTERNAL FUNCTION FM(T)
LET FM=SIN(1000*T+SIN(300*T))
END FUNCTION
----------------------------------------------------------------------------------
ラ音(A)=440Hzを基準として1オクターブ下はラ音(-A)=220Hzとなり
1オクターブ上はラ音(+A)=880Hzとなります。
つまり1オクターブ上は周波数が2倍になり、1オクターブ下は周波数が半分になります。
平均律では半音上の周波数は2^(1/12)を掛けていけばいいことになります。
https://ja.wikipedia.org/wiki/平均律
https://blog.sound-time.com/2021/08/blog-post_90.html
https://mvsica.sakura.ne.jp/eki/ekiinfo/tuning.html
平均律でドレミファソラシド音を生成します。
LET SAMPLINGFREQ=11025 ! サンプリング周波数
LET BASEFREQ=440 ! ラ音の周波数
LET NUM=8*SAMPLINGFREQ*.5 ! 8音*0.5秒
LET M=SAMPLINGFREQ*.5-1 ! 0.5秒
DIM LOUT(NUM)
DO
READ IF MISSING THEN EXIT DO:S$,A
LET FREQ=BASEFREQ*2^(A/12)
PRINT S$;FREQ;"Hz"
FOR J=0 TO M
LET N=N+1
LET X=J/M
LET LOUT(N)=SIN(J*FREQ/SAMPLINGFREQ*2*PI)*ENVELOPE(X)
NEXT J
LOOP
CALL WRITEWAV("平均律.wav",N,SAMPLINGFREQ,16,LOUT)
DATA "ド",-9,"レ",-7,"ミ",-5,"ファ",-4,"ソ",-2,"ラ",0,"シ",2,"+ド",3
END
EXTERNAL FUNCTION ENVELOPE(Z)
LET P=.1
LET Q=2.5
LET ENVELOPE=Z^P*(1-Z)^Q
END FUNCTION
以下略
----------------------------------------------------------------------------------
平均律での和音
https://ja.wikipedia.org/wiki/和音
LET SAMPLINGFREQ=11025
LET BASEFREQ=440 ! ラ音の周波数
LET NUM=SAMPLINGFREQ*4
LET M=SAMPLINGFREQ-1
DIM LOUT(NUM)
DO
READ IF MISSING THEN EXIT DO:A,B,C
LET FREQ1=BASEFREQ*2^(A/12)
LET FREQ2=BASEFREQ*2^(B/12)
LET FREQ3=BASEFREQ*2^(C/12)
FOR J=0 TO M
LET N=N+1
LET X=J/M
LET LOUT(N)=(SIN(J*FREQ1/SAMPLINGFREQ*2*PI)+SIN(J*FREQ2/SAMPLINGFREQ*2*PI)+SIN(J*FREQ3/SAMPLINGFREQ*2*PI))/3*ENVELOPE(X)
NEXT J
LOOP
CALL WRITEWAV("平均律和音.wav",N,SAMPLINGFREQ,16,LOUT)
DATA -9,-5,-2 ! C ド、ミ、ソ
DATA -7,-4,0 ! Dm レ、ファ、ラ
DATA -5,-2,2 ! Em ミ、ソ、シ
DATA -4,0,3 ! F ファ、ラ、ド
END
以下略
----------------------------------------------------------------------------------
下記は純正律でのドレミファソラシドです。
https://ja.wikipedia.org/wiki/純正律
LET SAMPLINGFREQ=11025
LET NUM=8*SAMPLINGFREQ*.5 ! 8音*0.5秒
DIM LOUT(NUM)
LET BASEFREQ=264 ! ド音
LET M=SAMPLINGFREQ*.5-1
DO
READ IF MISSING THEN EXIT DO:S$,A,B
LET FREQ=BASEFREQ*A/B
PRINT S$;FREQ;"Hz"
FOR J=0 TO M
LET N=N+1
LET X=J/M
LET LOUT(N)=SIN(J*FREQ/SAMPLINGFREQ*2*PI)*ENVELOPE(X)
NEXT J
LOOP
DATA "ド",1,1
DATA "レ",9,8
DATA "ミ",5,4
DATA "ファ",4,3
DATA "ソ",3,2
DATA "ラ",5,3
DATA "シ",15,8
DATA "+ド",2,1
CALL WRITEWAV("純正律.wav",N,SAMPLINGFREQ,16,LOUT)
END
以下略
----------------------------------------------------------------------------------
純正律での和音
LET SAMPLINGFREQ=11025
LET NUM=SAMPLINGFREQ*4
DIM LOUT(NUM)
LET BASEFREQ=264 ! ド音
LET M=SAMPLINGFREQ-1
DO
READ IF MISSING THEN EXIT DO:A,B,C,D,E,F
LET FREQ1=BASEFREQ*A/B
LET FREQ2=BASEFREQ*C/D
LET FREQ3=BASEFREQ*E/F
FOR J=0 TO M
LET N=N+1
LET X=J/M
LET LOUT(N)=(SIN(J*FREQ1/SAMPLINGFREQ*2*PI)+SIN(J*FREQ2/SAMPLINGFREQ*2*PI)+SIN(J*FREQ3/SAMPLINGFREQ*2*PI))/3*ENVELOPE(X)
NEXT J
LOOP
DATA 1,1,5,4,3,2 ! C
DATA 9,8,4,3,5,3 ! Dm
DATA 5,4,3,2,15,8 ! Em
DATA 4,3,5,3,2,1 ! F
CALL WRITEWAV("純正律和音.wav",N,SAMPLINGFREQ,16,LOUT)
END
以下略
----------------------------------------------------------------------------------
ピタゴラス音律によるドレミファソラシドです。
https://ja.wikipedia.org/wiki/ピタゴラス音律
LET SAMPLINGFREQ=11025
LET NUM=8*SAMPLINGFREQ*.5 ! 8音*0.5秒
DIM LOUT(NUM)
LET BASEFREQ=261 ! ド音
LET M=SAMPLINGFREQ*.5-1
DO
READ IF MISSING THEN EXIT DO:S$,A,B
LET FREQ=BASEFREQ*A/B
PRINT S$;FREQ;"Hz"
FOR J=0 TO M
LET N=N+1
LET X=J/M
LET LOUT(N)=SIN(J*FREQ/SAMPLINGFREQ*2*PI)*ENVELOPE(X)
NEXT J
LOOP
DATA "ド",1,1
DATA "レ",9,8
DATA "ミ",81,64
DATA "ファ",4,3
DATA "ソ",3,2
DATA "ラ",27,16
DATA "シ",243,128
DATA "+ド",2,1
CALL WRITEWAV("ピタゴラス音律.wav",N,SAMPLINGFREQ,16,LOUT)
END
以下略
----------------------------------------------------------------------------------
ピタゴラス音律での和音
LET SAMPLINGFREQ=11025
LET NUM=4*SAMPLINGFREQ
DIM LOUT(NUM)
LET BASEFREQ=261 ! ド音
LET M=SAMPLINGFREQ-1
DO
READ IF MISSING THEN EXIT DO:A,B,C,D,E,F
LET FREQ1=BASEFREQ*A/B
LET FREQ2=BASEFREQ*C/D
LET FREQ3=BASEFREQ*E/F
FOR J=0 TO M
LET N=N+1
LET X=J/M
LET LOUT(N)=(SIN(J*FREQ1/SAMPLINGFREQ*2*PI)+SIN(J*FREQ2/SAMPLINGFREQ*2*PI)+SIN(J*FREQ3/SAMPLINGFREQ*2*PI))/3*ENVELOPE(X)
NEXT J
LOOP
DATA 1,1,81,64,3,2 ! C
DATA 9,8,4,3,27,16 ! Dm
DATA 81,64,3,2,243,128 ! Em
DATA 4,3,27,16,2,1 ! F
CALL WRITEWAV("ピタゴラス音律和音.wav",N,SAMPLINGFREQ,16,LOUT)
END
以下略
----------------------------------------------------------------------------------
音楽演奏
https://decimalbasic.ninja-web.net/bbs2/1705.html
https://decimalbasic.ninja-web.net/bbs2/1706.html
https://decimalbasic.ninja-web.net/bbs2/1707.html
オクターブ下とオクターブ上の音を重ねています。
LET SAMPLINGFREQ=11025
LET TEMPO=140
DO
READ IF MISSING THEN EXIT DO:A$,T$
LET PLAYTIME=PLAYTIME+LENGTH(T$)
LOOP
LET NUM=PLAYTIME*SAMPLINGFREQ
DIM LOUT(NUM)
RESTORE
DO
READ IF MISSING THEN EXIT DO:A$,T$
LET FREQ=GETFREQ(A$)
LET M=SAMPLINGFREQ*LENGTH(T$)-1
FOR J=0 TO M
LET N=N+1
LET X=J/M
LET LOUT(N)=(SIN(J*FREQ/2/SAMPLINGFREQ*2*PI)+SIN(J*FREQ/SAMPLINGFREQ*2*PI)+SIN(J*FREQ*2/SAMPLINGFREQ*2*PI))*ENVELOPE(X)/3
NEXT J
LOOP
CALL WRITEWAV("キラキラ星.wav",N,SAMPLINGFREQ,16,LOUT)
!!PLAYSOUND "キラキラ星.wav" ! 再生
DATA +C,2,+C,2,+G,2,+G,2,+A,2,+A,2,+G,2.,R,8
DATA +F,2,+F,2,+E,2,+E,2,+D,2,+D,2,+C,2.,R,8,+G,2,+G,2
DATA +F,2,+F,2,+E,2,+E,2,+D,2.,R,8,+G,2,+G,2,+F,2,+F,2
DATA +E,2,+E,2,+D,2.,R,8,+C,2,+C,2,+G,2,+G,2,+A,2,+A,2
DATA +G,2.,R,8,+F,2,+F,2,+E,2,+E,2,+D,2,+D,2,+C,2.,R,8
FUNCTION LENGTH(T$)
SELECT CASE T$
CASE "1" ! 全音符
LET LENGTH=60/TEMPO*4
CASE "2" ! 2分音符
LET LENGTH=60/TEMPO*2
CASE "2." ! 符点2分音符
LET LENGTH=60/TEMPO*2*1.5
CASE "2-3" ! 2分3連符
LET LENGTH=60/TEMPO*2/1.5
CASE "4" ! 4分音符
LET LENGTH=60/TEMPO
CASE "4-3" ! 4分3連符
LET LENGTH=60/TEMPO/1.5
CASE "4." ! 符点4分音符
LET LENGTH=60/TEMPO*1.5
CASE "8" ! 8分音符
LET LENGTH=60/TEMPO/2
CASE "8-3" ! 8分3連符
LET LENGTH=60/TEMPO/2/1.5
CASE "8." ! 符点8分音符
LET LENGTH=60/TEMPO/2*1.5
CASE "16" ! 16分音符
LET LENGTH=60/TEMPO/4
CASE "16." ! 符点16分音符
LET LENGTH=60/TEMPO/4*1.5
END SELECT
END FUNCTION
END
EXTERNAL FUNCTION GETFREQ(KEY$)
RESTORE
FOR I=-21 TO 26
READ A$
IF A$=KEY$ THEN
LET GETFREQ=440*2^(I/12)
EXIT FOR
END IF
NEXT I
IF KEY$="R" THEN LET GETFREQ=0
DATA -C,"-C#",-D,"-D#",-E,-F,"-F#",-G,"-G#",-A,"-A#",-B
DATA C,"C#",D,"D#",E,F,"F#",G,"G#",A,"A#",B
DATA +C,"+C#",+D,"+D#",+E,+F,"+F#",+G,"+G#",+A,"+A#",+B
DATA ++C,"++C#",++D,"++D#",++E,++F,"++F#",++G,"++G#",++A,"++A#",++B
END FUNCTION
EXTERNAL FUNCTION ENVELOPE(Z)
LET P=.1
LET Q=2.5
LET ENVELOPE=Z^P*(1-Z)^Q
END FUNCTION
以下略
----------------------------------------------------------------------------------
LET TEMPO=120
CALL WRITEWAV("ちょうちょ.wav",N,SAMPLINGFREQ,16,LOUT)
DATA +G,4,+E,4,+E,2,+F,4,+D,4,+D,2,+C,4,+D,4,+E,4,+F,4
DATA +G,4,+G,4,+G,4.,R,8,+G,4,+E,4,+E,4,+E,4,+F,4,+D,4,+D,4,+D,4
DATA +C,4,+E,4,+G,4,+G,4,+E,4,+E,4,+E,4.,R,8,+D,4,+D,4,+D,4,+D,4,+D,4,+E,4,+F,2
DATA +E,4,+E,4,+E,4,+E,4,+E,4,+F,4,+G,4.,R,8,+G,4,+E,4,+E,4,+E,4,+F,4,+D,4,+D,4,+D,4
DATA +C,4,+E,4,+G,4,+G,4,+E,4,+E,4,+E,4.,R,8
以下略
----------------------------------------------------------------------------------
LET TEMPO=100
CALL WRITEWAV("きよしこの夜.wav",N,SAMPLINGFREQ,16,LOUT)
DATA G,4,A,8,G,4,E,2.,G,4.,A,8,G,4,E,2.,R,4
DATA +D,2,+D,4,B,2.,+C,2,+C,4,G,2,R,4,A,2,A,4,+C,4.,B,8,A,4,G,4.,A,8,G,4,E,2,R,4
DATA A,2,A,4,+C,4.,B,8,A,4,G,4.,A,8,G,4,E,2,R,4,+D,2,+D,4,+F,4.,+D,8,B,4,+C,2.,+E,2,R,4
DATA +C,4,G,4,E,4,G,4.,F,8,D,4,C,2.,C,2,R,4
以下略
----------------------------------------------------------------------------------
LET TEMPO=94
CALL WRITEWAV("大きな古時計.wav",N,SAMPLINGFREQ,16,LOUT)
DATA G,4,+C,4,B,8,+C,8,+D,4,+C,8,+D,8,+E,8,+E,8,+F,8,+E,8,A,4
DATA +D,8,+D,8,+C,4,+C,8,+C,8,B,4,A,8,B,8,+C,2.,G,8,G,8,+C,4
DATA B,8,+C,8,+D,4,+C,8,+D,8,+E,4,+F,8,+E,8,A,4,+D,8,+D,8
DATA +C,4,+C,8,+C,8,B,4,A,8,B,8,+C,2.,+C,8,+E,8,+G,4,+E,8
DATA +D,8,+C,4,B,8,+C,8,+D,8,+C,8,B,8,A,8,G,4,+C,8,+E,8
DATA +G,4,+E,8,+D,8,+C,4,B,8,+C,8,+D,2.,R,8,G,8,+C,8,+C,8,R,4
DATA +E,8,+E,8,+F,8,+E,8,A,4,+D,8,+D,8,+C,2,B,2,+C,2.,G,8,G,8
DATA +C,4,G,8,G,8,A,8,G,8,G,4,E,4,G,4,E,4,G,8,G,8,+C,4,G,8,G,8,A,4,G,8
DATA G,8,E,4,G,4,E,4,G,8,G,8,+C,8,+C,8,R,4,+D,4,R,4,+E,8,+E,8,+F,8
DATA +E,8,A,4,+D,8,+D,8,+C,2,B,2,+C,2.,R,4
以下略
----------------------------------------------------------------------------------
円周率で音楽演奏
円周率を8進数にして0→ド 1→レ 2→ミ 3→ファ 4→ソ 5→ラ 6→シ 7→+ドと置換して演奏してみた。
DIM TONE$(0 TO 7)
LET SAMPLINGFREQ=11025
LET TONE$(0)="C"
LET TONE$(1)="D"
LET TONE$(2)="E"
LET TONE$(3)="F"
LET TONE$(4)="G"
LET TONE$(5)="A"
LET TONE$(6)="B"
LET TONE$(7)="+C"
LET M=SAMPLINGFREQ*.25-1
DO
READ IF MISSING THEN EXIT DO:A
LET PLAYTIME=PLAYTIME+.25
LOOP
LET NUM=SAMPLINGFREQ*PLAYTIME
DIM LOUT(NUM)
RESTORE
DO
READ IF MISSING THEN EXIT DO:A
LET FREQ=GETFREQ(TONE$(A))
FOR J=0 TO M
LET N=N+1
LET X=J/M
LET LOUT(N)=(SIN(J*FREQ/2/SAMPLINGFREQ*2*PI)+SIN(J*FREQ/SAMPLINGFREQ*2*PI)+SIN(J*FREQ*2/SAMPLINGFREQ*2*PI))*ENVELOPE(X)/3
NEXT J
LOOP
CALL WRITEWAV("円周率.wav",N,SAMPLINGFREQ,16,LOUT)
DATA 1,1,0,3,7,5,5,2,4,2,1,0,2,6,4,3,0,2,1,5,1,4,2,3,0,6,3,0,5,0,5,6,0,0,6,7,0,1,6,3,2,1,1,2,2,0,1,1,1,6
DATA 0,2,1,0,5,1,4,7,6,3,0,7,2,0,0,2,0,2,7,3,7,2,4,6,1,6,6,1,1,6,3,3,1,0,4,5,0,5,1,2,0,2,0,7,4,6,1,6,1,5
END
以下略
----------------------------------------------------------------------------------
指数関数で音楽演奏
指数関数で16進数にして演奏してみた。
DIM TONE$(0 TO 15)
LET SAMPLINGFREQ=11025
LET TONE$(0)="C"
LET TONE$(1)="D"
LET TONE$(2)="E"
LET TONE$(3)="F"
LET TONE$(4)="G"
LET TONE$(5)="A"
LET TONE$(6)="B"
LET TONE$(7)="+C"
LET TONE$(8)="+D"
LET TONE$(9)="+E"
LET TONE$(10)="+F"
LET TONE$(11)="+G"
LET TONE$(12)="+A"
LET TONE$(13)="+B"
LET TONE$(14)="++C"
LET TONE$(15)="R"
LET M=SAMPLINGFREQ*.25-1
DO
READ IF MISSING THEN EXIT DO:A
LET PLAYTIME=PLAYTIME+.25
LOOP
LET NUM=SAMPLINGFREQ*PLAYTIME
DIM LOUT(NUM)
RESTORE
DO
READ IF MISSING THEN EXIT DO:A
LET FREQ=GETFREQ(TONE$(A))
FOR J=0 TO M
LET N=N+1
LET X=J/M
LET LOUT(N)=(SIN(J*FREQ/2/SAMPLINGFREQ*2*PI)+SIN(J*FREQ/SAMPLINGFREQ*2*PI)+SIN(J*FREQ*2/SAMPLINGFREQ*2*PI))*ENVELOPE(X)/3
NEXT J
LOOP
CALL WRITEWAV("exp(1).wav",N,SAMPLINGFREQ,16,LOUT)
DATA 11,7,14,1,5,1,6,2,8,10,14,13,2,10,6,10,11,15,7,1,5,8,8,0,9,12,15,4,15,3,12,7,6,2,14,7,1,6,0,15,3,8,11,4,13,10,5,6,10,7
DATA 8,4,13,9,0,4,5,1,9,0,12,15,14,15,3,2,4,14,7,7,3,8,9,2,6,12,15,11,14,5,15,4,11,15,8,13,8,13,8,12,3,1,13,7,6,3,13,10,0,6
END
以下略
----------------------------------------------------------------------------------
乱数で作曲
乱数使って演奏させてみた。
RANDOMIZE
DIM TONE$(0 TO 7),ONPU$(6)
LET SAMPLINGFREQ=11025
LET TEMPO=120
LET TONE$(0)="C"
LET TONE$(1)="D"
LET TONE$(2)="E"
LET TONE$(3)="F"
LET TONE$(4)="G"
LET TONE$(5)="A"
LET TONE$(6)="B"
LET TONE$(7)="+C"
LET ONPU$(1)="2"
LET ONPU$(2)="4"
LET ONPU$(3)="4."
LET ONPU$(4)="8"
LET ONPU$(5)="8."
LET ONPU$(6)="16"
LET L=100+INT(RND*100)-50
DIM TI$(L)
FOR I=1 TO L
LET M=INT(RND*6+1)
LET TI$(I)=ONPU$(M)
LET PLAYTIME=PLAYTIME+LENGTH(TI$(I))
NEXT I
LET NUM=SAMPLINGFREQ*PLAYTIME
DIM LOUT(NUM)
FOR I=1 TO L
LET P=INT(RND*8)
LET FREQ=GETFREQ(TONE$(P))
LET M=SAMPLINGFREQ*LENGTH(TI$(I))-1
PRINT TONE$(P);TI$(I);
IF MOD(I,10)=0 THEN PRINT
FOR J=0 TO M
LET N=N+1
LET X=J/M
LET LOUT(N)=(SIN(J*FREQ/2/SAMPLINGFREQ*2*PI)+SIN(J*FREQ/SAMPLINGFREQ*2*PI)+SIN(J*FREQ*2/SAMPLINGFREQ*2*PI))*ENVELOPE(X)/3
NEXT J
NEXT I
PRINT
CALL WRITEWAV("乱数.wav",N,SAMPLINGFREQ,16,LOUT)
END
以下略
----------------------------------------------------------------------------------
無限音階(無限に音程が上がり続けるように聞こえる。錯聴(耳の錯覚))
https://ja.wikipedia.org/wiki/シェパードトーン
https://decimalbasic.ninja-web.net/bbs2/1704.html
http://www.allisone.co.jp/html/Notes/Sound/Shepard-tone/Shepard-tone.html
LET SAMPLINGFREQ=44100
LET TEMPO=120
DO
READ IF MISSING THEN EXIT DO:A$,T$
LET PLAYTIME=PLAYTIME+LENGTH(T$)
LOOP
LET NUM=PLAYTIME*SAMPLINGFREQ
DIM LOUT(NUM)
RESTORE
DO
READ IF MISSING THEN EXIT DO:A$,T$
LET FREQ=GETFREQ(A$)
LET M=SAMPLINGFREQ*LENGTH(T$)-1
FOR J=0 TO M
LET N=N+1
LET X=J/M
LET LOUT(N)=(SIN(J*FREQ/4/SAMPLINGFREQ*2*PI)+SIN(J*FREQ/2/SAMPLINGFREQ*2*PI)+SIN(J*FREQ/SAMPLINGFREQ*2*PI)+SIN(J*FREQ*2/SAMPLINGFREQ*2*PI)+SIN(J*FREQ*4/SAMPLINGFREQ*2*PI))*ENVELOPE(X)/5
NEXT J
LOOP
CALL WRITEWAV("無限音階.wav",N,SAMPLINGFREQ,16,LOUT)
DATA C,4,D,4,E,4,F,4,-G,4,-A,4,-B,4
DATA C,4,D,4,E,4,F,4,-G,4,-A,4,-B,4
DATA C,4,D,4,E,4,F,4,-G,4,-A,4,-B,4
以下略
----------------------------------------------------------------------------------
電話をかける
https://decimalbasic.ninja-web.net/bbs2/1703.html
https://ja.wikipedia.org/wiki/DTMF
※受話器をスピーカーに近づけて鳴らすと電話がかかります。
DIM LOFREQ(12),HIFREQ(12)
FOR I=1 TO 12
READ LOFREQ(I),HIFREQ(I)
NEXT I
DATA 697,1209 !'1
DATA 697,1336 !'2
DATA 697,1447 !'3
DATA 770,1209 !'4
DATA 770,1336 !'5
DATA 770,1447 !'6
DATA 852,1209 !'7
DATA 852,1336 !'8
DATA 852,1447 !'9
DATA 941,1336 !'0
DATA 941,1209 !'*
DATA 941,1447 !'#
LET SAMPLINGFREQ=22050
LET NUMBER$="117" ! 電話番号
LET SECOND1=.3
LET SECOND2=.1
LET NUM=SAMPLINGFREQ*(SECOND1+SECOND2)*LEN(NUMBER$)
DIM OUT(NUM)
FOR J=1 TO LEN(NUMBER$)
LET K=POS("1234567890*#",MID$(NUMBER$,J,1))
IF K>0 THEN
FOR I=1 TO INT(SAMPLINGFREQ*SECOND1)
LET N=N+1
LET OUT(N)=.5*SIN(LOFREQ(K)*I/SAMPLINGFREQ*2*PI)+.5*SIN(HIFREQ(K)*I/SAMPLINGFREQ*2*PI)
NEXT I
FOR I=1 TO INT(SAMPLINGFREQ*SECOND2) !'区切り
LET N=N+1
LET OUT(N)=0
NEXT I
END IF
IF NUMBER$(J:J)="*" THEN LET NUMBER$(J:J)="*"
NEXT J
CALL WRITEWAV(NUMBER$&".wav",NUM,SAMPLINGFREQ,16,OUT)
END
以下略
----------------------------------------------------------------------------------
各周波数音を作成します
https://ja.wikipedia.org/wiki/聴覚
あなたは何Hzまで聞こえますか?
※必ずしも中低音スピーカーから高音域が出ているとは限りませんが...
人の可聴域は20Hz~20kHz位まで? 年代で聞こえる上限が違うようです。
もはや12kHz以上の音が聞こえないのはきっと安物低音スピーカーのせい!?
高周波音(嫌音器)を出して虫、猫、ハト、ゴキブリ、ネズミよけ ???
https://meetsmore.com/services/rat-control/media/86240
※スピーカーのボリュームに気を付けてください。
LET SAMPLINGFREQ=48000 ! サンプリング周波数
LET PLAYTIME=2 ! 再生時間
LET NUM=SAMPLINGFREQ*PLAYTIME
LET VOL=.5
DIM LOUT(NUM)
DO
DO
READ IF MISSING THEN EXIT DO:F$,FREQ
DATA 50Hz,50
DATA 100Hz,100
DATA 200Hz,200
DATA 400Hz,400
DATA 800Hz,800
DATA 1kHz,1000
DATA 2kHz,2000
DATA 4kHz,4000
DATA 8kHz,8000
DATA 10kHz,10000
DATA 11kHz,11000
DATA 12kHz,12000
DATA 13kHz,13000
DATA 14kHz,14000
DATA 15kHz,15000
DATA 16kHz,16000
DATA 17kHz,17000
DATA 18kHz,18000
DATA 19kHz,19000
DATA 20kHz,20000
DATA 21kHz,21000
DATA 22kHz,22000
DATA 23kHz,23000
FOR I=1 TO NUM
LET LOUT(I)=SIN(FREQ/SAMPLINGFREQ*I*2*PI)*VOL
NEXT I
CALL WRITEWAV("周波数"&F$&".wav",NUM,SAMPLINGFREQ,16,LOUT)
LOOP
END
以下略
----------------------------------------------------------------------------------
可聴域を調べます。
https://decimalbasic.ninja-web.net/bbs2/3786.html
https://ja.wikipedia.org/wiki/聴覚
https://www.sainokuni-rionet.jp/choice/7_index_detail.html
LET SW=1
IF SW=0 THEN
LET XMAX=200 ! 低音域
LET XMIN=10
ELSE
LET XMAX=22000 ! 高音域
LET XMIN=2000
END IF
LET F$="temporary.wav"
DO
LET XMID=INT((XMIN+XMAX)/2)
DO
PRINT XMID;"Hz"
CALL MAKEWAV(F$,XMID,1)
PLAYSOUND F$
INPUT PROMPT "聞こえましたか (Yes/No/Retry) ":A$
LOOP WHILE A$="R" OR A$="r"
IF SW=0 THEN
IF A$="Y" OR A$="y" THEN LET XMAX=XMID ELSE LET XMIN=XMID !'低音域
ELSE
IF A$="Y" OR A$="y" THEN LET XMIN=XMID ELSE LET XMAX=XMID !'高音域
END IF
LOOP UNTIL ABS(XMAX-XMIN)<10
PRINT "可聴域は";XMID;"Hzです"
FILE DELETE F$
END
EXTERNAL SUB MAKEWAV(F$,FREQ,PLAYTIME)
LET SAMPLINGFREQ=48000
LET NUM=SAMPLINGFREQ*PLAYTIME
DIM OUT(NUM)
FOR I=1 TO NUM
LET OUT(I)=SIN(FREQ/SAMPLINGFREQ*I*2*PI)*.5
NEXT I
CALL WRITEWAV(F$,NUM,SAMPLINGFREQ,16,OUT)
END SUB
以下略
----------------------------------------------------------------------------------
唸り音
周波数の近い音を重ねると唸りが発生します。
https://ja.wikipedia.org/wiki/うなり
※スピーカーのボリュームに気を付けてください。
LET SAMPLINGFREQ=44100 ! サンプリング周波数
LET NUM=SAMPLINGFREQ*3
DIM LOUT(NUM)
LET FREQ1=400 ! 400Hz
LET FREQ2=403 ! 403Hz
FOR I=1 TO NUM
LET LOUT(I)=SIN(FREQ1/SAMPLINGFREQ*I*2*PI)*.3+SIN(FREQ2/SAMPLINGFREQ*I*2*PI)*.3
NEXT I
CALL WRITEWAV("唸り.wav",NUM,SAMPLINGFREQ,16,LOUT)
END
以下略
----------------------------------------------------------------------------------
モールス
https://decimalbasic.ninja-web.net/bbs2/4712.html
https://ja.wikipedia.org/wiki/モールス符号
DIM LETTER$(50),MORSE$(50),OUT(11025*20)
DO
LET N=N+1
READ IF MISSING THEN EXIT DO:LETTER$(N),MORSE$(N)
LOOP
INPUT PROMPT "WORD=":WORD$
LET WORD$=UCASE$(WORD$)
FOR I=1 TO LEN(WORD$)
FOR J=1 TO N
IF WORD$(I:I)=LETTER$(J) THEN
FOR K=1 TO LEN(MORSE$(J))
LET L=VAL(MORSE$(J)(K:K))
CALL MAKESOUND(L,OUT)
NEXT K
CALL MAKESOUND(2,OUT)
EXIT FOR
END IF
NEXT J
IF WORD$(I:I)="?" THEN LET WORD$(I:I)="?"
IF WORD$(I:I)="/" THEN LET WORD$(I:I)="/"
NEXT I
CALL WRITEWAV(WORD$&".wav",C,SAMPLINGFREQ,16,OUT)
DATA A,01
DATA B,1000
DATA C,1010
DATA D,100
DATA E,0
DATA F,0010
DATA G,110
DATA H,0000
DATA I,00
DATA J,0111
DATA K,101
DATA L,0100
DATA M,11
DATA N,10
DATA O,111
DATA P,0110
DATA Q,1101
DATA R,010
DATA S,000
DATA T,1
DATA U,001
DATA V,0001
DATA W,011
DATA X,1001
DATA Y,1011
DATA Z,1100
DATA 1,0111
DATA 2,00111
DATA 3,00011
DATA 4,00001
DATA 5,00000
DATA 6,10000
DATA 7,11000
DATA 8,11100
DATA 9,11110
DATA 0,11111
DATA ".",010101
DATA ",",110011
DATA "?",001100
DATA "!",101011
DATA "-",100001
DATA "/",10010
DATA "@",011010
DATA "(",10110
DATA ")",101101
DATA " ",2222222
SUB MAKESOUND(SW,OUT())
LET VOL=.5
LET SAMPLINGFREQ=11025
SELECT CASE SW
CASE 0
LET FREQ=400
FOR II=1 TO SAMPLINGFREQ*.25
LET C=C+1
LET OUT(C)=SIN(FREQ/SAMPLINGFREQ*II*2*PI)*VOL
NEXT II
LET FREQ=0
FOR II=1 TO SAMPLINGFREQ*.25 ! 区切り
LET C=C+1
LET OUT(C)=SIN(FREQ/SAMPLINGFREQ*II*2*PI)*VOL
NEXT II
CASE 1
LET FREQ=400
FOR II=1 TO SAMPLINGFREQ*.75
LET C=C+1
LET OUT(C)=SIN(FREQ/SAMPLINGFREQ*II*2*PI)*VOL
NEXT II
LET FREQ=0
FOR II=1 TO SAMPLINGFREQ*.25 ! 区切り
LET C=C+1
LET OUT(C)=SIN(FREQ/SAMPLINGFREQ*II*2*PI)*VOL
NEXT II
CASE 2
LET FREQ=0
FOR II=1 TO SAMPLINGFREQ*.75 ! 文字間区切り
LET C=C+1
LET OUT(C)=SIN(FREQ/SAMPLINGFREQ*II*2*PI)*VOL
NEXT II
END SELECT
END SUB
END
以下略
----------------------------------------------------------------------------------
ガンマ波サウンド ?
これ聞いてボケ防止になる?
https://gammawavesound.com/
https://www.project.gammawavesound.com/
https://wellnesslab-report.jp/pj/gamma-tech/40hzgamma-waves/
LET SAMPLINGFREQ=8000
LET NUM=SAMPLINGFREQ*5
DIM LOUT(NUM)
LET FREQ=40
FOR K=1 TO NUM
LET VOL=SIN(K*FREQ/SAMPLINGFREQ*2*PI)*.5+.5
LET LOUT(K)=VOL*SIN(1000/SAMPLINGFREQ*K*2*PI)
NEXT K
CALL WRITEWAV("ガンマ波サウンド.wav",NUM,SAMPLINGFREQ,16,LOUT)
END
以下略
----------------------------------------------------------------------------------
LET SAMPLINGFREQ=22050 !'サンプリング周波数
LET VOL=.5 !'音量
LET PLAYTIME=3
LET FREQ=440
LET FREQ2=2
LET NUM=SAMPLINGFREQ*PLAYTIME
DIM OUT(NUM)
FOR K=1 TO NUM
LET LFO=10*SIN(FREQ2*K/SAMPLINGFREQ*2*PI)
LET OUT(K)=SIN(K*(FREQ+LFO)/SAMPLINGFREQ*2*PI)*VOL
NEXT K
CALL WRITEWAV("ヴィブラート.wav",NUM,SAMPLINGFREQ,16,OUT)
END
以下略
----------------------------------------------------------------------------------
LET SAMPLINGFREQ=22050 !'サンプリング周波数
LET PLAYTIME=3
LET FREQ=440
LET FREQ2=6
LET NUM=SAMPLINGFREQ*PLAYTIME
DIM OUT(NUM)
FOR K=1 TO NUM
LET VOL=SIN(FREQ2*K/SAMPLINGFREQ*2*PI)*.2+.5
LET OUT(K)=SIN(K*FREQ/SAMPLINGFREQ*2*PI)*VOL
NEXT K
CALL WRITEWAV("トレモロ.wav",NUM,SAMPLINGFREQ,16,OUT)
END
以下略
----------------------------------------------------------------------------------
LET FREQ1=770
LET FREQ2=960
LET SAMPLINGFREQ=22050
LET VOL=.5
LET ITER=4 ! 繰り返し数
LET TI=.5 ! 継続時間
LET PLAYTIME=ITER*2*TI ! 総時間
LET NUM=SAMPLINGFREQ*PLAYTIME
DIM OUT(NUM)
FOR I=1 TO ITER
FOR J=1 TO 2
IF J=1 THEN LET FREQ=FREQ1 ELSE LET FREQ=FREQ2
FOR K=0 TO SAMPLINGFREQ*TI-1
LET N=N+1
LET X=K/(SAMPLINGFREQ*TI)
LET OUT(N)=SIN(FREQ/SAMPLINGFREQ*K*2*PI)*VOL
NEXT K
NEXT J
NEXT I
CALL WRITEWAV("サイレン.wav",N,SAMPLINGFREQ,16,OUT)
END
以下略
----------------------------------------------------------------------------------
LET SAMPLINGFREQ=44100
LET NUM=SAMPLINGFREQ*5
DIM LOUT(NUM)
FOR I=1 TO NUM
LET LOUT(I)=SIN(MIX(100,10000,I/NUM)/SAMPLINGFREQ*I*2*PI)*.5
NEXT I
CALL WRITEWAV("上昇音.wav",NUM,SAMPLINGFREQ,16,LOUT)
FOR I=1 TO NUM
LET LOUT(I)=SIN(INT(MIX(100,10000,I/NUM)/100)*100/SAMPLINGFREQ*I*2*PI)*.5
NEXT I
CALL WRITEWAV("上昇音2.wav",NUM,SAMPLINGFREQ,16,LOUT)
END
EXTERNAL FUNCTION MIX(A,B,T)
LET MIX=A*(1-T)+B*T
END FUNCTION
以下略
Re: wavファイル書き出しルーチン - しばっち
2024/10/13 (Sun) 06:50:56
32ビット浮動小数型によるwav書き出し
PCMデータ値は-1~1までの値です。
このサブルーチンの仕様はWRITEWAVと同じですがSAMPLEBITの指定は要りません。(32bit固定)
EXTERNAL SUB WRITEWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,LOUT(),ROUT())
OPTION CHARACTER BYTE
IF POS(LCASE$(F$),".wav")=0 THEN LET F$=F$&".wav"
OPEN #1:NAME F$
ERASE #1
IF NUM=0 THEN LET NUM=UBOUND(LOUT,1)
LET HEADERSIZE=16
LET WAVETYPE=3
LET SAMPLEBIT=32
LET PLAYTIME=NUM/SAMPLINGFREQ
LET SAMPLESIZE=SAMPLEBIT/8*CHANNEL
LET DATARATE = SAMPLESIZE * SAMPLINGFREQ
LET PCMSIZE=INT(DATARATE*PLAYTIME)
LET WAVEFILESIZE=PCMSIZE+36
PRINT #1:"RIFF";
PRINT #1:DWORD$(WAVEFILESIZE);
PRINT #1:"WAVEfmt ";
PRINT #1:DWORD$(HEADERSIZE);
PRINT #1:WORD$(WAVETYPE);
PRINT #1:WORD$(CHANNEL);
PRINT #1:DWORD$(SAMPLINGFREQ);
PRINT #1:DWORD$(DATARATE);
PRINT #1:WORD$(SAMPLESIZE);
PRINT #1:WORD$(SAMPLEBIT);
PRINT #1:"data";
PRINT #1:DWORD$(PCMSIZE);
FOR K=1 TO NUM
FOR CH=1 TO CHANNEL
SELECT CASE CH
CASE 1
LET LOUT(K)=ATN(LOUT(K))/(PI/2) ! -∞~∞ → -1~1
PRINT #1:FLOAT32$(LOUT(K));
CASE 2
LET ROUT(K)=ATN(ROUT(K))/(PI/2) ! -∞~∞ → -1~1
PRINT #1:FLOAT32$(ROUT(K));
CASE ELSE ! 3チャンネル以上は無視
END SELECT
NEXT CH
NEXT K
CLOSE #1
END SUB
EXTERNAL FUNCTION FLOAT32$(X) ! IEEE754 32bit float
OPTION CHARACTER BYTE
OPTION BASE 0
DIM B(32)
IF X<0 THEN LET B(0)=1
IF X<>0 THEN
IF ABS(X)<1 THEN
DO WHILE 2^(N+1)>ABS(X)
LET N=N-1
LOOP
LET N=N+1
ELSE
DO WHILE 2^(N+1)<ABS(X)
LET N=N+1
LOOP
END IF
LET NN=N
LET N=N+127
FOR I=1 TO 8
IF BITAND(N,2^(8-I))<>0 THEN LET B(I)=1
NEXT I
LET T=(ABS(X)-2^NN)/2^NN
FOR I=9 TO 31
LET T=T*2
IF T>=1 THEN
LET B(I)=1
LET T=T-INT(T)
END IF
NEXT I
END IF
LET AA$=CHR$(B(0)*128+B(1)*64+B(2)*32+B(3)*16+B(4)*8+B(5)*4+B(6)*2+B(7))
LET BB$=CHR$(B(8)*128+B(9)*64+B(10)*32+B(11)*16+B(12)*8+B(13)*4+B(14)*2+B(15))
LET CC$=CHR$(B(16)*128+B(17)*64+B(18)*32+B(19)*16+B(20)*8+B(21)*4+B(22)*2+B(23))
LET DD$=CHR$(B(24)*128+B(25)*64+B(26)*32+B(27)*16+B(28)*8+B(29)*4+B(30)*2+B(31))
LET FLOAT32$=DD$&CC$&BB$&AA$
END FUNCTION
----------------------------------------------------------------------
64ビット浮動小数型によるwav書き出し
仕様はWRITEWAVと同じですがSAMPLEBITの指定は要りません。(64bit固定)
エクスプローラのプレビュー(Windows Media Player)では再生不可。
VLCメディアプレイヤーにて再生確認。
https://www.videolan.org/vlc/index.ja.html
EXTERNAL SUB WRITEWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,LOUT(),ROUT())
OPTION CHARACTER BYTE
IF POS(LCASE$(F$),".wav")=0 THEN LET F$=F$&".wav"
OPEN #1:NAME F$
ERASE #1
LET HEADERSIZE=16
LET WAVETYPE=3
LET SAMPLEBIT=64
LET PLAYTIME=NUM/SAMPLINGFREQ
LET SAMPLESIZE=SAMPLEBIT/8*CHANNEL
LET DATARATE = SAMPLESIZE * SAMPLINGFREQ
LET PCMSIZE=INT(DATARATE*PLAYTIME)
LET WAVEFILESIZE=PCMSIZE+36
PRINT #1:"RIFF";
PRINT #1:DWORD$(WAVEFILESIZE);
PRINT #1:"WAVEfmt ";
PRINT #1:DWORD$(HEADERSIZE);
PRINT #1:WORD$(WAVETYPE);
PRINT #1:WORD$(CHANNEL);
PRINT #1:DWORD$(SAMPLINGFREQ);
PRINT #1:DWORD$(DATARATE);
PRINT #1:WORD$(SAMPLESIZE);
PRINT #1:WORD$(SAMPLEBIT);
PRINT #1:"data";
PRINT #1:DWORD$(PCMSIZE);
FOR K=1 TO NUM
FOR CH=1 TO CHANNEL
SELECT CASE CH
CASE 1
LET LOUT(K)=ATN(LOUT(K))/(PI/2) ! -∞~∞ → -1~1
PRINT #1:PACKDBL$(LOUT(K));
CASE 2
LET ROUT(K)=ATN(ROUT(K))/(PI/2) ! -∞~∞ → -1~1
PRINT #1:PACKDBL$(ROUT(K));
CASE ELSE ! 3チャンネル以上は無視
END SELECT
NEXT CH
NEXT K
CLOSE #1
END SUB
Re: wavファイル書き出しルーチン - しばっち
2024/10/13 (Sun) 06:52:06
aiffファイル書き出し
https://decimalbasic.ninja-web.net/log/article/b/basic/105/kjnrqf/kjnrqf.html
PCMデータ値は-1~1までの値です。
このサブルーチンの仕様はWRITEWAVと同じです。つまりCALL WRITEWAV(...をCALL WRITEAIFF(...と置き換えできます。
EXTERNAL SUB WRITEAIFF(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT(),ROUT())
OPTION CHARACTER BYTE
IF F$="" THEN EXIT SUB
IF POS(LCASE$(F$),".aiff")=0 AND POS(LCASE$(F$),".aif")=0 THEN LET F$=F$&".aiff"
SELECT CASE SAMPLEBIT
CASE 8,16,24,32
CASE ELSE
LET SAMPLEBIT=16
END SELECT
IF NUM=0 THEN LET NUM=UBOUND(LOUT,1)
OPEN #1:NAME F$
ERASE #1
PRINT #1:"FORM";
PRINT #1:MKL2$(46+2*NUM);
PRINT #1:"AIFF";
PRINT #1:"COMM";
PRINT #1:MKL2$(18);
PRINT #1:MKI2$(CHANNEL);
PRINT #1:MKL2$(NUM);
PRINT #1:MKI2$(SAMPLEBIT);
PRINT #1:FLOAT80$(SAMPLINGFREQ);
PRINT #1:"SSND";
PRINT #1:MKL2$(2*NUM+8);
PRINT #1:REPEAT$(CHR$(0),8);
FOR I=1 TO NUM
FOR CH=1 TO CHANNEL
SELECT CASE CH
CASE 1
LET LOUT(I)=MIN(1,MAX(LOUT(I),-1))
SELECT CASE SAMPLEBIT
CASE 8
PRINT #1:CHR$(LOUT(I)*127+128);
CASE 16
PRINT #1:MKI2$(LOUT(I)*2^15);
CASE 24
PRINT #1:MKM2$(LOUT(I)*2^23);
CASE 32
PRINT #1:MKL2$(LOUT(I)*2^31);
END SELECT
CASE 2
LET ROUT(I)=MIN(1,MAX(ROUT(I),-1))
SELECT CASE SAMPLEBIT
CASE 8
PRINT #1:CHR$(ROUT(I)*127+128);
CASE 16
PRINT #1:MKI2$(ROUT(I)*2^15);
CASE 24
PRINT #1:MKM2$(ROUT(I)*2^23);
CASE 32
PRINT #1:MKL2$(ROUT(I)*2^31);
END SELECT
CASE ELSE
END SELECT
NEXT CH
NEXT I
CLOSE #1
END SUB
EXTERNAL FUNCTION MKI2$(A) ! BIG-ENDIAN
OPTION CHARACTER BYTE
DECLARE STRING A$,B$
LET A=INT(A)
IF A<0 THEN LET A=A+65536
LET A$=CHR$(MOD(A,256))
LET B$=CHR$(INT(A/256))
LET MKI2$=B$&A$
END FUNCTION
EXTERNAL FUNCTION MKM2$(A) ! BIG-ENDIAN
OPTION CHARACTER BYTE
DECLARE STRING A$,B$
LET A=INT(A)
IF A<0 THEN LET A=A+2^24
LET A$=CHR$(MOD(A,256))
LET B$=CHR$(MOD(INT(A/256),256))
LET C$=CHR$(MOD(INT(A/65536),256))
LET MKM2$=C$&B$&A$
END FUNCTION
EXTERNAL FUNCTION MKL2$(A) ! BIG-ENDIAN
OPTION CHARACTER BYTE
DECLARE STRING A$,B$,C$,D$
LET A=INT(A)
IF A<0 THEN LET A=A+2^32
LET A$=CHR$(MOD(A,256))
LET B$=CHR$(MOD(INT(A/256),256))
LET C$=CHR$(MOD(INT(A/65536),256))
LET D$=CHR$(MOD(INT(A/16777216),256))
LET MKL2$=D$&C$&B$&A$
END FUNCTION
EXTERNAL FUNCTION FLOAT80$(X) ! モトローラIEEE754 80bit FLOAT
OPTION CHARACTER BYTE
OPTION BASE 0
DIM B(80)
IF X<0 THEN LET B(0)=1
IF X<>0 THEN
IF ABS(X)<1 THEN
DO WHILE 2^N>ABS(X)
LET N=N-1
LOOP
LET N=N+1
ELSE
DO WHILE 2^N<ABS(X)
LET N=N+1
LOOP
END IF
LET NN=N
LET N=N+16382
FOR I=1 TO 15
IF BITAND(N,2^(15-I))<>0 THEN LET B(I)=1
NEXT I
LET T=ABS(X)/2^NN
FOR I=16 TO 79
LET T=T*2
IF T>=1 THEN
LET B(I)=1
LET T=T-INT(T)
END IF
NEXT I
END IF
LET AA$=CHR$(B(0)*128+B(1)*64+B(2)*32+B(3)*16+B(4)*8+B(5)*4+B(6)*2+B(7))
LET BB$=CHR$(B(8)*128+B(9)*64+B(10)*32+B(11)*16+B(12)*8+B(13)*4+B(14)*2+B(15))
LET CC$=CHR$(B(16)*128+B(17)*64+B(18)*32+B(19)*16+B(20)*8+B(21)*4+B(22)*2+B(23))
LET DD$=CHR$(B(24)*128+B(25)*64+B(26)*32+B(27)*16+B(28)*8+B(29)*4+B(30)*2+B(31))
LET EE$=CHR$(B(32)*128+B(33)*64+B(34)*32+B(35)*16+B(36)*8+B(37)*4+B(38)*2+B(39))
LET FF$=CHR$(B(40)*128+B(41)*64+B(42)*32+B(43)*16+B(44)*8+B(45)*4+B(46)*2+B(47))
LET GG$=CHR$(B(48)*128+B(49)*64+B(50)*32+B(51)*16+B(52)*8+B(53)*4+B(54)*2+B(55))
LET HH$=CHR$(B(56)*128+B(57)*64+B(58)*32+B(59)*16+B(60)*8+B(61)*4+B(62)*2+B(63))
LET II$=CHR$(B(64)*128+B(65)*64+B(66)*32+B(67)*16+B(68)*8+B(69)*4+B(70)*2+B(71))
LET JJ$=CHR$(B(72)*128+B(73)*64+B(74)*32+B(75)*16+B(76)*8+B(77)*4+B(78)*2+B(79))
LET FLOAT80$=AA$&BB$&CC$&DD$&EE$&FF$&GG$&HH$&II$&JJ$
END FUNCTION
--------------------------------------------------------------------------------------------------
AU/SNDファイル書き出し
仕様はWRITEWAVと同じです。
EXTERNAL SUB WRITESND(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT(),ROUT())
IF F$="" THEN EXIT SUB
LET OFFSET=24
LET DATASIZE=-1
SELECT CASE SAMPLEBIT
CASE 8
LET ENCODING=2
CASE 16
LET ENCODING=3
CASE 24
LET ENCODING=4
CASE 32
LET ENCODING=5
CASE ELSE
LET ENCODING=3
END SELECT
IF POS(LCASE$(F$),".snd")=0 AND POS(LCASE$(F$),".au")=0 THEN LET F$=F$&".au"
OPEN #1:NAME F$
ERASE #1
PRINT #1:".snd";
PRINT #1:MKL2$(OFFSET);
PRINT #1:MKL2$(DATASIZE);
PRINT #1:MKL2$(ENCODING);
PRINT #1:MKL2$(SAMPLINGFREQ);
PRINT #1:MKL2$(CHANNEL);
FOR I=1 TO NUM
FOR CH=1 TO CHANNEL
SELECT CASE CH
CASE 1
LET LOUT(I)=MIN(1,MAX(LOUT(I),-1))
SELECT CASE ENCODING
CASE 2
PRINT #1:CHR$(LOUT(I)*127+128);
CASE 3
PRINT #1:MKI2$(LOUT(I)*2^15);
CASE 4
PRINT #1:MKM2$(LOUT(I)*2^23);
CASE 5
PRINT #1:MKL2$(LOUT(I)*2^31);
END SELECT
CASE 2
LET ROUT(I)=MIN(1,MAX(ROUT(I),-1))
SELECT CASE ENCODING
CASE 2
PRINT #1:CHR$(ROUT(I)*127+128);
CASE 3
PRINT #1:MKI2$(ROUT(I)*2^15);
CASE 4
PRINT #1:MKM2$(ROUT(I)*2^23);
CASE 5
PRINT #1:MKL2$(ROUT(I)*2^31);
END SELECT
CASE ELSE
END SELECT
NEXT CH
NEXT I
CLOSE #1
END SUB
以下略
Re: wavファイル書き出しルーチン - しばっち
2024/10/13 (Sun) 06:53:16
RF64形式ファイルの書き出し(wavファイルの64bit版!?)
理論上2^64-1(18446744073709551615)バイト迄対応しています。(※wavファイルは4Gバイトまで)
http://d0ec7852ef61.seesaa.net/article/183599913.html
https://tech.ebu.ch/docs/tech/tech3306v1_0.pdf
VLCメディアプレイヤーで再生確認。
https://www.videolan.org/vlc/index.ja.html
このサブルーチンの仕様はWRITEWAVと同じです。つまりCALL WRITEWAV(...をCALL WRITERF64(...と置き換えできます。
EXTERNAL SUB WRITERF64(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT(),ROUT())
OPTION CHARACTER BYTE
IF POS(LCASE$(F$),".rf64")=0 AND POS(LCASE$(F$),".wav")=0 AND POS(LCASE$(F$),".w64")=0 THEN LET F$=F$&".wav"
OPEN #1:NAME F$
ERASE #1
SELECT CASE SAMPLEBIT
CASE 8,16,24
CASE ELSE
LET SAMPLEBIT=16
END SELECT
IF NUM=0 THEN LET NUM=UBOUND(LOUT,1)
LET HEADERSIZE=28
LET CHUNKSIZE=40
LET BLOCKSIZE=SAMPLEBIT/8*CHANNEL
LET DATASIZE=NUM*BLOCKSIZE
LET RIFFSIZE=DATASIZE+98
LET COMPRESS=SAMPLINGFREQ*BLOCKSIZE
LET BITPERSAMPLE=SAMPLEBIT
LET CHANNELMASK=3
LET CBSIZE=22
PRINT #1:"RF64";
PRINT #1:DWORD$(-1);
PRINT #1:"WAVE";
PRINT #1:"ds64";
PRINT #1:DWORD$(HEADERSIZE);
PRINT #1:WORD64$(RIFFSIZE);
PRINT #1:WORD64$(DATASIZE);
PRINT #1:WORD64$(NUM);
PRINT #1:DWORD$(0);
PRINT #1:"fmt ";
PRINT #1:DWORD$(CHUNKSIZE);
PRINT #1:HEX$("FFFE");
PRINT #1:WORD$(CHANNEL);
PRINT #1:DWORD$(SAMPLINGFREQ);
PRINT #1:DWORD$(COMPRESS);
PRINT #1:WORD$(BLOCKSIZE);
PRINT #1:WORD$(BITPERSAMPLE);
PRINT #1:WORD$(CBSIZE);
PRINT #1:WORD$(SAMPLEBIT);
PRINT #1:DWORD$(CHANNELMASK);
PRINT #1:HEX$("00000001");
PRINT #1:HEX$("0000");
PRINT #1:HEX$("0010");
PRINT #1:HEX$("AA000080");
PRINT #1:HEX$("719B3800");
PRINT #1:"data";
PRINT #1:DWORD$(NUM*BLOCKSIZE)
LET A=INT(NUM/100)
PRINT "書き出し中"
FOR K=1 TO NUM
IF MOD(K,INT(NUM/A))=0 AND INT(K/A)<>R THEN
LET R=INT(K/A)
PRINT R;"%"
END IF
FOR CH=1 TO CHANNEL
SELECT CASE CH
CASE 1
LET LOUT(K)=MIN(1,MAX(LOUT(K),-1))
SELECT CASE SAMPLEBIT
CASE 8
PRINT #1:CHR$(LOUT(K)*127+128);
CASE 16
PRINT #1:WORD$(LOUT(K)*2^15);
CASE 24
PRINT #1:WORD24$(LOUT(K)*2^23);
END SELECT
CASE 2
LET ROUT(K)=MIN(1,MAX(ROUT(K),-1))
SELECT CASE SAMPLEBIT
CASE 8
PRINT #1:CHR$(ROUT(K)*127+128);
CASE 16
PRINT #1:WORD$(ROUT(K)*2^15);
CASE 24
PRINT #1:WORD24$(ROUT(K)*2^23);
END SELECT
CASE ELSE
END SELECT
NEXT CH
NEXT K
CLOSE #1
END SUB
EXTERNAL FUNCTION WORD24$(A)
OPTION CHARACTER BYTE
DECLARE STRING A$,B$,C$
LET A=INT(A)
IF A<0 THEN LET A=A+2^24
LET A$=CHR$(MOD(A,256))
LET B$=CHR$(MOD(INT(A/256),256))
LET C$=CHR$(MOD(INT(A/65536),256))
LET WORD24$=A$&B$&C$
END FUNCTION
EXTERNAL FUNCTION WORD64$(A)
OPTION CHARACTER BYTE
DECLARE STRING A$,B$,C$,D$,E$,F$,G$,H$
LET A=INT(A)
IF A<0 THEN LET A=A+2^64
LET A$=CHR$(MOD(A,256))
LET B$=CHR$(MOD(INT(A/2^8),256))
LET C$=CHR$(MOD(INT(A/2^16),256))
LET D$=CHR$(MOD(INT(A/2^24),256))
LET E$=CHR$(MOD(INT(A/2^32),256))
LET F$=CHR$(MOD(INT(A/2^40),256))
LET G$=CHR$(MOD(INT(A/2^48),256))
LET H$=CHR$(MOD(INT(A/2^56),256))
LET WORD64$=A$&B$&C$&D$&E$&F$&G$&H$
END FUNCTION
EXTERNAL FUNCTION HEX$(X$)
OPTION CHARACTER BYTE
FOR I=1 TO LEN(X$) STEP 2
LET S$=CHR$(BVAL(X$(I:I+1),16))&S$
NEXT I
LET HEX$=S$
END FUNCTION
Re: wavファイル書き出しルーチン - しばっち
2024/10/13 (Sun) 06:54:28
cafファイル書き出し(64ビット版aiffファイル ?)
理論上2^64-1(18446744073709551615)バイト迄対応しています。
https://developer.apple.com/library/archive/documentation/MusicAudio/Reference/CAFSpec/CAF_spec/CAF_spec.html
このサブルーチンの仕様はWRITEWAVと同じです。つまりCALL WRITEWAV(...をCALL WRITECAF(...と置き換えできます。
EXTERNAL SUB WRITECAF(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT(),ROUT())
OPTION CHARACTER BYTE
IF F$="" THEN EXIT SUB
IF POS(LCASE$(F$),".caf")=0 THEN LET F$=F$&".caf"
OPEN #1:NAME F$
ERASE #1
SELECT CASE SAMPLEBIT
CASE 16,32
CASE ELSE
LET SAMPLEBIT=16
END SELECT
IF NUM=0 THEN LET NUM=UBOUND(LOUT,1)
PRINT #1:"caff"; ! ファイルタイプ
PRINT #1:BWORD16$(1); ! バージョン
PRINT #1:BWORD16$(0); ! ファイルフラグ
PRINT #1:"desc"; ! チャンク
PRINT #1:BWORD64$(32); ! サイズ
PRINT #1:DOUBLE64$(SAMPLINGFREQ); ! サンプリング周波数
PRINT #1:"lpcm"; ! ID
PRINT #1:BWORD32$(0); ! フォーマットフラグ(big-endian-integer)
PRINT #1:BWORD32$(SAMPLEBIT/8*CHANNEL); ! BytePerPacket
PRINT #1:BWORD32$(1); ! FramePerPacket
PRINT #1:BWORD32$(CHANNEL); ! ChannelPerFrame
PRINT #1:BWORD32$(SAMPLEBIT); ! BitPerChannel
PRINT #1:"chan"; ! チャンク
PRINT #1:BWORD64$(12); ! サイズ
IF CHANNEL=1 THEN PRINT #1:CHR$(0);CHR$(100);CHR$(0);CHR$(1); ! ChannelLayout
IF CHANNEL=2 THEN PRINT #1:CHR$(0);CHR$(101);CHR$(0);CHR$(2); ! ChannelLayout
PRINT #1:BWORD32$(0); ! ChannelBitmap
PRINT #1:BWORD32$(0); ! NumberDescription
PRINT #1:"data";
PRINT #1:BWORD64$(NUM*CHANNEL*SAMPLEBIT/8); ! サイズ
LET A=INT(NUM/100)
PRINT "書き出し中"
FOR K=1 TO NUM
IF MOD(K,INT(NUM/A))=0 AND INT(K/A)<>R THEN
LET R=INT(K/A)
PRINT R;"%"
END IF
FOR CH=1 TO CHANNEL
SELECT CASE CH
CASE 1
LET LOUT(K)=MIN(1,MAX(LOUT(K),-1))
SELECT CASE SAMPLEBIT
CASE 16
PRINT #1:BWORD16$(LOUT(K)*2^15);
CASE 32
PRINT #1:BWORD32$(LOUT(K)*2^31);
END SELECT
CASE 2
LET ROUT(K)=MIN(1,MAX(ROUT(K),-1))
SELECT CASE SAMPLEBIT
CASE 16
PRINT #1:BWORD16$(ROUT(K)*2^15);
CASE 32
PRINT #1:BWORD32$(ROUT(K)*2^31);
END SELECT
CASE ELSE
END SELECT
NEXT CH
NEXT K
CLOSE #1
END SUB
EXTERNAL FUNCTION BWORD16$(A) ! BIG-ENDIAN
OPTION CHARACTER BYTE
DECLARE STRING A$,B$
LET A=INT(A)
IF A<0 THEN LET A=A+65536
LET A$=CHR$(MOD(A,256))
LET B$=CHR$(INT(A/256))
LET BWORD16$=B$&A$
END FUNCTION
EXTERNAL FUNCTION BWORD32$(A) ! BIG-ENDIAN
OPTION CHARACTER BYTE
DECLARE STRING A$
LET A=INT(A)
IF A<0 THEN LET A=A+2^32
FOR I=1 TO 4
LET A$=CHR$(MOD(A,256))&A$
LET A=INT(A/256)
NEXT I
LET BWORD32$=A$
END FUNCTION
EXTERNAL FUNCTION BWORD64$(A) ! BIG-ENDIAN
OPTION CHARACTER BYTE
DECLARE STRING A$
LET A=INT(A)
IF A<0 THEN LET A=A+2^64
FOR I=1 TO 8
LET A$=CHR$(MOD(A,256))&A$
LET A=INT(A/256)
NEXT I
LET BWORD64$=A$
END FUNCTION
EXTERNAL FUNCTION DOUBLE64$(X) ! BIG-ENDIAN
OPTION CHARACTER BYTE
LET A$=PACKDBL$(X)
LET DOUBLE64$=A$(8:8)&A$(7:7)&A$(6:6)&A$(5:5)&A$(4:4)&A$(3:3)&A$(2:2)&A$(1:1)
END FUNCTION
Re: wavファイル書き出しルーチン - しばっち
2024/10/13 (Sun) 06:55:46
rawファイルの書き出し
https://en.wikipedia.org/wiki/Raw_audio_format
ヘッダーはなくPCMデータのみの単純なファイルです。
このサブルーチンの仕様は一部パラメータが異なりますが置き換えできます。
BIGENDIANに対応しています。
EXTERNAL SUB WRITERAW(F$,NUM,CHANNEL,SAMPLEBIT,BIGENDIAN,LOUT(),ROUT())
OPTION CHARACTER BYTE
IF POS(LCASE$(F$),".raw")=0 THEN LET F$=F$&".raw"
SELECT CASE SAMPLEBIT
CASE 8,16,24,32,64
CASE ELSE
LET SAMPLEBIT=16
END SELECT
IF NUM=0 THEN LET NUM=UBOUND(LOUT,1)
OPEN #1:NAME F$
ERASE #1
LET A=INT(NUM/100)
PRINT "書き出し中"
FOR K=1 TO NUM
IF MOD(K,INT(NUM/A))=0 AND INT(K/A)<>R THEN
LET R=INT(K/A)
PRINT R;"%"
END IF
FOR CH=1 TO CHANNEL
SELECT CASE CH
CASE 1
LET LOUT(K)=MIN(1,MAX(LOUT(K),-1))
SELECT CASE SAMPLEBIT
CASE 8
PRINT #1:CHR$(LOUT(K)*127+128);
CASE 16
LET A$=WORD$(LOUT(K)*2^15)
IF BIGENDIAN<>0 THEN LET A$=A$(2:2)&A$(1:1)
PRINT #1:A$;
!CASE 24
! LET A$=WORD24$(LOUT(K)*2^23)
! IF BIGENDIAN<>0 THEN LET A$=A$(3:3)&A$(2:2)&A$(1:1)
! PRINT #1:A$;
CASE 32
LET A$=DWORD$(LOUT(K)*2^31)
IF BIGENDIAN<>0 THEN LET A$=A$(4:4)&A$(3:3)&A$(2:2)&A$(1:1)
PRINT #1:A$;
!CASE 64
! LET A$=WORD64$(LOUT(K)*2^63)
! IF BIGENDIAN<>0 THEN LET A$=A$(8:8)&A$(7:7)&A$(6:6)&A$(5:5)&A$(4:4)&A$(3:3)&A$(2:2)&A$(1:1)
! PRINT #1:A$;
END SELECT
CASE 2
LET ROUT(K)=MIN(1,MAX(ROUT(K),-1))
SELECT CASE SAMPLEBIT
CASE 8
PRINT #1:CHR$(ROUT(K)*127+128);
CASE 16
LET A$=WORD$(ROUT(K)*2^15)
IF BIGENDIAN<>0 THEN LET A$=A$(2:2)&A$(1:1)
PRINT #1:A$;
!CASE 24
! LET A$=WORD24$(ROUT(K)*2^23)
! IF BIGENDIAN<>0 THEN LET A$=A$(3:3)&A$(2:2)&A$(1:1)
! PRINT #1:A$;
CASE 32
LET A$=DWORD$(ROUT(K)*2^31)
IF BIGENDIAN<>0 THEN LET A$=A$(4:4)&A$(3:3)&A$(2:2)&A$(1:1)
PRINT #1:A$;
!CASE 64
! LET A$=WORD64$(ROUT(K)*2^63)
! IF BIGENDIAN<>0 THEN LET A$=A$(8:8)&A$(7:7)&A$(6:6)&A$(5:5)&A$(4:4)&A$(3:3)&A$(2:2)&A$(1:1)
! PRINT #1:A$;
END SELECT
CASE ELSE
END SELECT
NEXT CH
NEXT K
CLOSE #1
END SUB
以下略
Re: wavファイル書き出しルーチン - しばっち
2024/10/13 (Sun) 06:57:37
csvファイル書き出し
下記のようなフォーマットで出力します。
2chチャンネル(ステレオ)までの出力です。
-1~1までのPCMデータを与えます。
このサブルーチンの仕様はWRITEWAVと同じです。つまりCALL WRITEWAV(...をCALL WRITECSV(...と置き換えできます。
CSVファイルなのでもちろんエクセルでも読み込めます。
始めの4行はwavファイルに書き戻す時に必要なヘッダー情報です。
書き戻さない場合は必要ありません。
sample.csv
44100 ---> サンプリング周波数(8000,16000,32000,11025,22050,44100,48000,96000等)
16 ---> サンプルビット数(8,16,24,32)
2 ---> チャンネル数 1ch~8ch位 ?
132300 ---> この行以下のPCMデータ数(サンプル数)ここまでがヘッダー情報
2.84797490584979E-2 , 5.68670237962044E-2 ---> PCMデータ 2ch分(左、右) -1~1迄の範囲
5.68670237962044E-2 , .112996053647038
8.50696501583163E-2 , .167658672951382
.112996053647038 , .220145495506271
.140555556665827 , .269775371593091
.167658672951382 , .315904227623731
.194217398137347 , .357933424629859
.220145495506271 , .395317527122704
: :
: : 以下省略
EXTERNAL SUB WRITECSV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT(),ROUT())
IF F$="" THEN EXIT SUB
IF POS(LCASE$(F$),".csv")=0 THEN LET F$=F$&".csv"
OPEN #1:NAME F$
ERASE #1
SELECT CASE SAMPLEBIT
CASE 8,16,24,32
CASE ELSE
LET SAMPLEBIT=16
END SELECT
IF NUM=0 THEN LET NUM=UBOUND(LOUT,1)
PRINT #1:SAMPLINGFREQ
PRINT #1:SAMPLEBIT
PRINT #1:CHANNEL
PRINT #1:NUM
LET A=INT(NUM/100)
PRINT "書き出し中"
FOR K=1 TO NUM
IF MOD(K,INT(NUM/A))=0 AND INT(K/A)<>R THEN
LET R=INT(K/A)
PRINT R;"%"
END IF
SELECT CASE CHANNEL
CASE 1
LET LOUT(K)=MIN(1,MAX(LOUT(K),-1))
PRINT #1:LOUT(K)
CASE 2
LET LOUT(K)=MIN(1,MAX(LOUT(K),-1))
LET ROUT(K)=MIN(1,MAX(ROUT(K),-1))
PRINT #1:LOUT(K);",";ROUT(K)
CASE ELSE
END SELECT
NEXT K
CLOSE #1
END SUB
Re: wavファイル書き出しルーチン - しばっち
2024/10/13 (Sun) 06:58:52
SONY WAVE64ファイル形式の書き込み
https://wiki.multimedia.cx/index.php/Sony_Wave64
http://martinleese.epizy.com/MyTemporaryDownloads/Sony_Wave64.pdf?i=1
理論上2^64-1(18446744073709551615)バイト迄対応しています。
このサブルーチンの仕様はWRITEWAVと同じです。つまりCALL WRITEWAV(...をCALL WRITEW64(...と置き換えできます。
MPC-HCにて再生確認
https://www.gigafree.net/media/MediaPlayer/mediaplayerclassic.html
https://mpc-hc.softonic.jp/
EXTERNAL SUB WRITEW64(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT(),ROUT())
OPTION CHARACTER BYTE
IF POS(LCASE$(F$),".w64")=0 THEN LET F$=F$&".w64"
SELECT CASE SAMPLEBIT
CASE 16,32
CASE ELSE
LET SAMPLEBIT=16
END SELECT
IF NUM=0 THEN LET NUM=UBOUND(LOUT,1)
LET PLAYTIME=NUM/SAMPLINGFREQ
LET SAMPLESIZE=SAMPLEBIT/8*CHANNEL
LET DATARATE = SAMPLESIZE * SAMPLINGFREQ
LET SIZE=INT(DATARATE*PLAYTIME)
OPEN #1:NAME F$
ERASE #1
PRINT #1:HEXCHR$("726966662E91CF11A5D628DB04C10000");
PRINT #1:WORD64$(SIZE+80);
PRINT #1:HEXCHR$("77617665F3ACD3118CD100C04F8EDB8A");
PRINT #1:HEXCHR$("666D7420F3ACD3118CD100C04F8EDB8A");
PRINT #1:WORD64$(40);
PRINT #1:WORD$(1);
PRINT #1:WORD$(CHANNEL);
PRINT #1:DWORD$(SAMPLINGFREQ);
PRINT #1:DWORD$(DATARATE);
PRINT #1:WORD$(SAMPLESIZE);
PRINT #1:WORD$(SAMPLEBIT);
PRINT #1:HEXCHR$("64617461F3ACD3118CD100C04F8EDB8A");
PRINT #1:WORD64$(SIZE);
LET A=INT(NUM/100)
PRINT "書き出し中"
FOR K=1 TO NUM
IF MOD(K,INT(NUM/A))=0 AND INT(K/A)<>R THEN
LET R=INT(K/A)
PRINT R;"%"
END IF
FOR CH=1 TO CHANNEL
SELECT CASE CH
CASE 1
LET LOUT(K)=MIN(1,MAX(LOUT(K),-1))
SELECT CASE SAMPLEBIT
CASE 16
PRINT #1:WORD$(LOUT(K)*2^15);
CASE 32
PRINT #1:DWORD$(LOUT(K)*2^31);
END SELECT
CASE 2
LET ROUT(K)=MIN(1,MAX(ROUT(K),-1))
SELECT CASE SAMPLEBIT
CASE 16
PRINT #1:WORD$(ROUT(K)*2^15);
CASE 32
PRINT #1:DWORD$(ROUT(K)*2^31);
END SELECT
CASE ELSE
END SELECT
NEXT CH
NEXT K
CLOSE #1
END SUB
EXTERNAL FUNCTION HEXCHR$(A$)
OPTION CHARACTER BYTE
FOR I=1 TO LEN(A$) STEP 2
LET S$=S$&CHR$(BVAL(A$(I:I+1),16))
NEXT I
LET HEXCHR$=S$
END FUNCTION
以下略
Re: wavファイル書き出しルーチン - しばっち
2024/10/13 (Sun) 07:00:35
C/C++によるWAVファイル書き込みルーチン 32bit版のみです。(64bit版dllの提供はしていません)
このサブルーチンの仕様はWRITEWAVと同じです。置き換え可能です。
VC++2022でコンパイルしました。(Windows 7 SP1以上)
https://visualstudio.microsoft.com/ja/downloads/
EXTERNAL SUB WRITEWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT(),ROUT())
OPTION CHARACTER BYTE
IF POS(LCASE$(F$),".wav")=0 THEN LET F$=F$&".wav"
SELECT CASE SAMPLEBIT
CASE 8,16,24,32
CASE ELSE
LET SAMPLEBIT=16
END SELECT
IF NUM=0 THEN LET NUM=UBOUND(LOUT,1)
LET HEADERSIZE=16
LET WAVETYPE=1
LET PLAYTIME=NUM/SAMPLINGFREQ
LET SAMPLESIZE=SAMPLEBIT/8*CHANNEL
LET DATARATE = SAMPLESIZE * SAMPLINGFREQ
LET PCMSIZE=SAMPLESIZE*NUM
LET WAVEFILESIZE=PCMSIZE+36
LET HEADER$="RIFF"&DWORD$(WAVEFILESIZE)&"WAVEfmt "&DWORD$(HEADERSIZE)&WORD$(WAVETYPE)&WORD$(CHANNEL)&DWORD$(SAMPLINGFREQ)&DWORD$(DATARATE)&WORD$(SAMPLESIZE)&WORD$(SAMPLEBIT)&"data"&DWORD$(PCMSIZE)
LET DAT$=REPEAT$(" ",PCMSIZE)
FOR K=1 TO NUM
SELECT CASE CHANNEL
CASE 1
LET LOUT(K)=RANGE(LOUT(K))
SELECT CASE SAMPLEBIT
CASE 8
LET DAT$(K:K)=CHR$(LOUT(K)*127+128)
CASE 16
LET DAT$(2*K-1:2*K)=WORD$(LOUT(K)*2^15)
!CASE 24
! LET DAT$(3*K-2:3*K)=WORD24$(LOUT(K)*2^23)
CASE 32
LET DAT$(4*K-3:4*K)=DWORD$(LOUT(K)*2^31)
END SELECT
CASE 2
LET LOUT(K)=RANGE(LOUT(K))
LET ROUT(K)=RANGE(ROUT(K))
SELECT CASE SAMPLEBIT
CASE 8
LET DAT$(2*K-1:2*K)=CHR$(LOUT(K)*127+128)&CHR$(ROUT(K)*127+128)
CASE 16
LET DAT$(4*K-3:4*K)=WORD$(LOUT(K)*2^15)&WORD$(ROUT(K)*2^15)
!CASE 24
! LET DAT$(6*K-5:6*K)=WORD24$(LOUT(K)*2^23)&WORD24$(ROUT(K)*2^23)
CASE 32
LET DAT$(8*K-7:8*K)=DWORD$(LOUT(K)*2^31)&DWORD$(ROUT(K)*2^31)
END SELECT
CASE ELSE
END SELECT
NEXT K
LET ERR=FILEWRITE2(F$,0,LEN(HEADER$&DAT$),HEADER$&DAT$)
IF ERR>0 THEN PRINT "書き込みエラー"
END SUB
EXTERNAL FUNCTION FILEWRITE(F$,SEEK,SIZE,DAT$)
OPTION CHARACTER BYTE
ASSIGN ".\DLL\fileread.dll","filewrite"
END FUNCTION
EXTERNAL FUNCTION FILEWRITE2(F$,SEEK,SIZE,DAT$)
OPTION CHARACTER BYTE
ASSIGN ".\DLL\fileread2.dll","filewrite"
END FUNCTION
EXTERNAL FUNCTION RANGE(X)
LET RANGE=MIN(1,MAX(X,-1))
!RANGE=2/(1+EXP(-X))-1
!RANGE=TANH(X)
!RANGE=ATN(X)/(PI/2)
END FUNCTION
以下略
Re: wavファイル書き出しルーチン - しばっち
2024/10/13 (Sun) 07:01:37
C/C++ライブラリーによるDLL版の書き込みルーチンです。32bit版のみです。
https://github.com/adamstark/AudioFile
ヘッダーライブラリーです。ヘッダーファイルをインクルードするだけで使えます。
上記URLからダウンロードしてVC++2022で下記cppソースからコンパイルできます。
データ値は-1~1までの値です。
このサブルーチンの仕様はWRITEWAVと同じです。置き換え可能です。
VC++2022でコンパイルしました。
下記からダウンロードしてください。(wave.zip)29.9 MB (31,410,628 バイト)
https://66.gigafile.nu/0121-d5d86eb73a1f6ce256c440f69c9462329
ダウンロード期限:2025年1月21日(火)
パスワード:設定していません
EXTERNAL SUB WRITEWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT(),ROUT())
OPTION CHARACTER BYTE
IF F$="" THEN EXIT SUB
IF NUM=0 THEN LET NUM=UBOUND(LOUT,1)
LET L$=REPEAT$(" ",8*NUM)
LET R$=REPEAT$(" ",8*NUM)
IF POS(LCASE$(F$),".wav")=0 THEN LET F$=F$&".wav"
SELECT CASE SAMPLEBIT
CASE 8,16,24,32
CASE ELSE
LET SAMPLEBIT=16
END SELECT
FOR I=0 TO NUM-1
LET LOUT(I+1)=MIN(1,MAX(LOUT(I+1),-1))
LET L$(8*I+1:8*I+8)=PACKDBL$(LOUT(I+1))
IF CHANNEL=2 THEN
LET ROUT(I+1)=MIN(1,MAX(ROUT(I+1),-1))
LET R$(8*I+1:8*I+8)=PACKDBL$(ROUT(I+1))
END IF
NEXT I
LET ERR=WRITEWAV_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,L$,R$)
IF ERR>0 THEN PRINT "書き込みエラー"
FUNCTION WRITEWAV_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,L$,R$)
OPTION CHARACTER BYTE
ASSIGN ".\DLL\writewav.dll","writewav"
END FUNCTION
END SUB
EXTERNAL SUB WRITEAIFF(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT(),ROUT())
OPTION CHARACTER BYTE
IF F$="" THEN EXIT SUB
LET L$=REPEAT$(" ",8*NUM)
LET R$=REPEAT$(" ",8*NUM)
IF POS(LCASE$(F$),".aiff")=0 AND POS(LCASE$(F$),".aif")=0 THEN LET F$=F$&".aiff"
SELECT CASE SAMPLEBIT
CASE 8,16,24,32
CASE ELSE
LET SAMPLEBIT=16
END SELECT
FOR I=0 TO NUM-1
LET LOUT(I+1)=MIN(1,MAX(LOUT(I+1),-1))
LET L$(8*I+1:8*I+8)=PACKDBL$(LOUT(I+1))
IF CHANNEL=2 THEN
LET ROUT(I+1)=MIN(1,MAX(ROUT(I+1),-1))
LET R$(8*I+1:8*I+8)=PACKDBL$(ROUT(I+1))
END IF
NEXT I
LET ERR=WRITEAIFF_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,L$,R$)
IF ERR>0 THEN PRINT "書き込みエラー"
FUNCTION WRITEAIFF_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,L$,R$)
OPTION CHARACTER BYTE
ASSIGN ".\DLL\writewav.dll","writeaiff"
END FUNCTION
END SUB
-----------------------------------------------------------------------------------------
writewav.cpp
#include "AudioFile.h"
using namespace std;
extern "C" __declspec(dllexport) int writewav(char *name,int num,int channel,samplingfreq,int samplebit,double *lout,double *rout)
{
AudioFile<double> audioFile;
audioFile.setAudioBufferSize (channel, num);
audioFile.setBitDepth (samplebit);
audioFile.setSampleRate (samplingfreq);
for (int i = 0; i < num; i++)
for (int ch = 0; ch < channel; ch++)
{
if (ch==0) audioFile.samples[ch][i]=lout[i];
if (ch==1) audioFile.samples[ch][i]=rout[i];
}
if(audioFile.save(name, AudioFileFormat::Wave)) return 0;
else return 1;
}
extern "C" __declspec(dllexport) int writeaiff(char *name,int num,int channel,int samplingfreq,int samplebit,double *lout,double *rout)
{
AudioFile<double> audioFile;
audioFile.setAudioBufferSize (channel, num);
audioFile.setBitDepth (samplebit);
audioFile.setSampleRate (samplingfreq);
for (int i = 0; i < num; i++)
for (int ch = 0; ch < channel; ch++)
{
if (ch==0) audioFile.samples[ch][i]=lout[i];
if (ch==1) audioFile.samples[ch][i]=rout[i];
}
if(audioFile.save (name, AudioFileFormat::Aiff)) return 0;
else return 1;
}
Re: wavファイル書き出しルーチン - しばっち
2024/10/13 (Sun) 07:02:36
C/C++ライブラリーによるDLL版の書き込みルーチンです。32bit版のみです。
https://github.com/audionamix/wave
このサブルーチンの仕様はWRITEWAVと同じです。置き換え可能です。
このプログラムではfloat型を使用していますが精度的には問題ないかと思います。(double型未対応のため)
VC++2022でコンパイルしました。
EXTERNAL SUB WRITEWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT(),ROUT())
OPTION CHARACTER BYTE
IF F$="" THEN EXIT SUB
IF NUM=0 THEN LET NUM=UBOUND(LOUT,1)
LET L$=REPEAT$(" ",8*NUM)
LET R$=REPEAT$(" ",8*NUM)
IF POS(LCASE$(F$),".wav")=0 THEN LET F$=F$&".wav"
SELECT CASE SAMPLEBIT
CASE 8,16,24,32
CASE ELSE
LET SAMPLEBIT=16
END SELECT
FOR I=0 TO NUM-1
LET LOUT(I+1)=MIN(1,MAX(LOUT(I+1),-1))
LET L$(8*I+1:8*I+8)=PACKDBL$(LOUT(I+1))
IF CHANNEL=2 THEN
LET ROUT(I+1)=MIN(1,MAX(ROUT(I+1),-1))
LET R$(8*I+1:8*I+8)=PACKDBL$(ROUT(I+1))
END IF
NEXT I
LET ERR=WRITEWAV_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,L$,R$)
IF ERR>0 THEN PRINT "書き込みエラー"
FUNCTION WRITEWAV_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,L$,R$)
OPTION CHARACTER BYTE
ASSIGN ".\DLL\writewave.dll","writewav"
END FUNCTION
END SUB
----------------------------------------------------------------------------------------
writewave.cpp
#include "wave/file.h"
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
using namespace wave;
float range(float x)
{
if (x<-1.0) x=-1.0;
if (x>1.0) x=1.0;
return x;
}
extern "C" __declspec(dllexport) int writewav(char *name,int num,int channel,int samplingfreq,int samplebit,double *lout,double *rout)
{
int ch,i;
File write_file;
vector<float> content;
for(i=0; i<num; i++) {
for (ch=0; ch<channel; ch++) {
if(ch==0) content.push_back((float)lout[i]);
if(ch==1) content.push_back((float)rout[i]);
}
}
Error err=write_file.Open(name, OpenMode::kOut);
if(err) return 1;
write_file.set_sample_rate(samplingfreq);
write_file.set_bits_per_sample(samplebit);
write_file.set_channel_number(channel);
err=write_file.Write(content);
if(err) return 1;
return 0;
}
Re: wavファイル書き出しルーチン - しばっち
2024/10/13 (Sun) 07:03:40
C/C++ライブラリーによるDLL版の書き込みルーチンです。32bit版のみです。
https://github.com/DIYFXWorld/Other
https://github.com/Numerix-DSP/wav_file
ヘッダーライブラリーです。ヘッダーファイルをインクルードするだけで使えます。
上記URLからダウンロードしてVC++2022で下記cppソースからコンパイルできます。
このサブルーチンの仕様はWRITEWAVと同じです。置き換え可能です。
VC++2022でコンパイルしました。
EXTERNAL SUB WRITEWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT(),ROUT())
OPTION CHARACTER BYTE
IF F$="" THEN EXIT SUB
IF NUM=0 THEN LET NUM=UBOUND(LOUT,1)
LET LOUT$=REPEAT$(" ",8*NUM)
LET ROUT$=REPEAT$(" ",8*NUM)
IF POS(LCASE$(F$),".wav")=0 THEN LET F$=F$&".wav"
IF POS("8 16 24 32",STR$(SAMPLEBIT))=0 THEN LET SAMPLEBIT=16
FOR I=0 TO NUM-1
LET LOUT(I+1)=MIN(1,MAX(LOUT(I+1),-1))
LET LOUT$(8*I+1:8*I+8)=PACKDBL$(LOUT(I+1))
IF CHANNEL=2 THEN
LET ROUT(I+1)=MIN(1,MAX(ROUT(I+1),-1))
LET ROUT$(8*I+1:8*I+8)=PACKDBL$(ROUT(I+1))
END IF
NEXT I
LET ERR=WRITEWAV_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT$,ROUT$)
FUNCTION WRITEWAV_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT$,ROUT$)
OPTION CHARACTER BYTE
ASSIGN ".\DLL\writewave2.dll","writewav"
END FUNCTION
!FUNCTION WRITEWAV_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT$,ROUT$)
! OPTION CHARACTER BYTE
! ASSIGN ".\DLL\writewave3.dll","writewav"
!END FUNCTION
END SUB
----------------------------------------------------------------------------------------
writewave2.cpp
#include "wave.hpp"
using namespace std;
extern "C" __declspec(dllexport) int writewav(char *name,int num,int channel,int samplingfreq,int samplebit,double *lin,double *rin)
{
int i;
wave <double> src1(samplingfreq,num); //mono
wave <double> src2(samplingfreq,num,2); //stereo
for(i=0; i<num; ++i)
{
switch(channel)
{
case 1:
src1[i]=lin[i];
break;
case 2:
src2.L[i]=lin[i];
src2.R[i]=rin[i];
}
}
switch (samplebit)
{
case 8:
{
if (channel==1) save(name, src1,8);
else save(name,src2,8);
break;
}
case 16:
{
if (channel==1) save(name, src1);
else save(name,src2);
break;
}
default:
{
if (channel==1) save(name, src1);
else save(name,src2);
}
}
return 0;
}
----------------------------------------------------------------------------------------
writewave3.c
#include <stdio.h>
#include <stdlib.h>
#include "wav_file.h"
#include <math.h>
__declspec(dllexport) int writewav(char *name,int num,int channel,int samplingfreq,int samplebit,double *lin,double *rin)
{
FILE *fpwav;
int count;
double *dat;
WAV_FILE_INFO wavinfo;
if ((fpwav=fopen(name,"wb"))==NULL) return 3;
wavinfo.SampleRate = samplingfreq;
wavinfo.NumberOfSamples = num*channel;
wavinfo.NumberOfChannels = channel;
wavinfo.WordLength = samplebit;
wavinfo.BytesPerSample = samplebit/8*channel;
wavinfo.DataFormat = 1;
dat=(double *)malloc(sizeof(double)*num*channel);
if(dat==NULL) return 2;
for(int i=0; i<num; i++)
{
if(channel==1) {
dat[i*channel]=lin[i]*pow(2.0,samplebit-1);
}
if(channel==2) {
dat[i*channel]=lin[i]*pow(2.0,samplebit-1);
dat[i*channel+1]=rin[i]*pow(2.0,samplebit-1);
}
}
wav_write_header(fpwav,wavinfo);
wav_write_data (dat, fpwav, wavinfo, num*channel);
fclose(fpwav);
free(dat);
return 0;
}
Re: wavファイル書き出しルーチン - しばっち
2024/10/13 (Sun) 07:04:59
C/C++ライブラリーによるDLL版の書き込みルーチンです。32bit版のみです。
http://www.mega-nerd.com/libsndfile/
このサブルーチンの仕様はWRITEWAVと同じです。置き換え可能です。
実行には別途libsndfile-1.dllが必要です。
VC++2022でコンパイルしました。
EXTERNAL SUB WRITEWAV(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT(),ROUT())
OPTION CHARACTER BYTE
IF F$="" THEN EXIT SUB
IF NUM=0 THEN LET NUM=UBOUND(LOUT,1)
LET DAT$=REPEAT$(" ",8*NUM*CHANNEL)
IF POS(LCASE$(F$),".wav")=0 THEN LET F$=F$&".wav"
FOR I=0 TO NUM-1
LET LOUT(I+1)=MIN(1,MAX(LOUT(I+1),-1))
LET ROUT(I+1)=MIN(1,MAX(ROUT(I+1),-1))
IF CHANNEL=1 THEN
LET DAT$(8*I+1:8*I+8)=PACKDBL$(LOUT(I+1))
END IF
IF CHANNEL=2 THEN
LET DAT$(16*I+1:16*I+8)=PACKDBL$(LOUT(I+1))
LET DAT$(16*I+9:16*I+16)=PACKDBL$(ROUT(I+1))
END IF
NEXT I
LET ERR=WRITEWAV_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT$)
IF ERR>0 THEN PRINT "書き込みエラー"
FUNCTION WRITEWAV_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT$)
OPTION CHARACTER BYTE
ASSIGN ".\DLL\writesnd.dll","writewav"
END FUNCTION
END SUB
EXTERNAL SUB WRITEAIFF(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT(),ROUT())
OPTION CHARACTER BYTE
IF F$="" THEN EXIT SUB
IF NUM=0 THEN LET NUM=UBOUND(LOUT,1)
LET DAT$=REPEAT$(" ",8*NUM*CHANNEL)
IF POS(LCASE$(F$),".aiff")=0 AND POS(LCASE$(F$),".aif")=0 THEN LET F$=F$&".aiff"
FOR I=0 TO NUM-1
LET LOUT(I+1)=MIN(1,MAX(LOUT(I+1),-1))
LET ROUT(I+1)=MIN(1,MAX(ROUT(I+1),-1))
IF CHANNEL=1 THEN
LET DAT$(8*I+1:8*I+8)=PACKDBL$(LOUT(I+1))
END IF
IF CHANNEL=2 THEN
LET DAT$(16*I+1:16*I+8)=PACKDBL$(LOUT(I+1))
LET DAT$(16*I+9:16*I+16)=PACKDBL$(ROUT(I+1))
END IF
NEXT I
LET ERR=WRITEAIFF_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT$)
IF ERR>0 THEN PRINT "書き込みエラー"
FUNCTION WRITEAIFF_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT$)
OPTION CHARACTER BYTE
ASSIGN ".\DLL\writesnd.dll","writeaiff"
END FUNCTION
END SUB
EXTERNAL SUB WRITEAU(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT(),ROUT())
OPTION CHARACTER BYTE
IF F$="" THEN EXIT SUB
IF NUM=0 THEN LET NUM=UBOUND(LOUT,1)
LET DAT$=REPEAT$(" ",8*NUM*CHANNEL)
IF POS(LCASE$(F$),".au")=0 AND POS(LCASE$(F$),".snd")=0 THEN LET F$=F$&".au"
FOR I=0 TO NUM-1
LET LOUT(I+1)=MIN(1,MAX(LOUT(I+1),-1))
LET ROUT(I+1)=MIN(1,MAX(ROUT(I+1),-1))
IF CHANNEL=1 THEN
LET DAT$(8*I+1:8*I+8)=PACKDBL$(LOUT(I+1))
END IF
IF CHANNEL=2 THEN
LET DAT$(16*I+1:16*I+8)=PACKDBL$(LOUT(I+1))
LET DAT$(16*I+9:16*I+16)=PACKDBL$(ROUT(I+1))
END IF
NEXT I
LET ERR=WRITEAU_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT$)
IF ERR>0 THEN PRINT "書き込みエラー"
FUNCTION WRITEAU_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT$)
OPTION CHARACTER BYTE
ASSIGN ".\DLL\writesnd.dll","writeau"
END FUNCTION
END SUB
EXTERNAL SUB WRITEFLAC(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT(),ROUT())
OPTION CHARACTER BYTE
IF F$="" THEN EXIT SUB
IF NUM=0 THEN LET NUM=UBOUND(LOUT,1)
LET DAT$=REPEAT$(" ",8*NUM*CHANNEL)
IF POS(LCASE$(F$),".flac")=0 THEN LET F$=F$&".flac"
FOR I=0 TO NUM-1
LET LOUT(I+1)=MIN(1,MAX(LOUT(I+1),-1))
LET ROUT(I+1)=MIN(1,MAX(ROUT(I+1),-1))
IF CHANNEL=1 THEN
LET DAT$(8*I+1:8*I+8)=PACKDBL$(LOUT(I+1))
END IF
IF CHANNEL=2 THEN
LET DAT$(16*I+1:16*I+8)=PACKDBL$(LOUT(I+1))
LET DAT$(16*I+9:16*I+16)=PACKDBL$(ROUT(I+1))
END IF
NEXT I
LET ERR=WRITEFLAC_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT$)
IF ERR>0 THEN PRINT "書き込みエラー"
FUNCTION WRITEFLAC_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT$)
OPTION CHARACTER BYTE
ASSIGN ".\DLL\writesnd.dll","writeflac"
END FUNCTION
END SUB
EXTERNAL SUB WRITECAF(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT(),ROUT())
OPTION CHARACTER BYTE
IF F$="" THEN EXIT SUB
IF NUM=0 THEN LET NUM=UBOUND(LOUT,1)
LET DAT$=REPEAT$(" ",8*NUM*CHANNEL)
IF POS(LCASE$(F$),".caf")=0 THEN LET F$=F$&".caf"
FOR I=0 TO NUM-1
LET LOUT(I+1)=MIN(1,MAX(LOUT(I+1),-1))
LET ROUT(I+1)=MIN(1,MAX(ROUT(I+1),-1))
IF CHANNEL=1 THEN
LET DAT$(8*I+1:8*I+8)=PACKDBL$(LOUT(I+1))
END IF
IF CHANNEL=2 THEN
LET DAT$(16*I+1:16*I+8)=PACKDBL$(LOUT(I+1))
LET DAT$(16*I+9:16*I+16)=PACKDBL$(ROUT(I+1))
END IF
NEXT I
LET ERR=WRITECAF_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT$)
IF ERR>0 THEN PRINT "書き込みエラー"
FUNCTION WRITECAF_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT$)
OPTION CHARACTER BYTE
ASSIGN ".\DLL\writesnd.dll","writecaf"
END FUNCTION
END SUB
EXTERNAL SUB WRITERF64(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT(),ROUT())
OPTION CHARACTER BYTE
IF F$="" THEN EXIT SUB
IF NUM=0 THEN LET NUM=UBOUND(LOUT,1)
LET DAT$=REPEAT$(" ",8*NUM*CHANNEL)
IF POS(LCASE$(F$),".wav")=0 THEN LET F$=F$&".wav"
FOR I=0 TO NUM-1
LET LOUT(I+1)=MIN(1,MAX(LOUT(I+1),-1))
LET ROUT(I+1)=MIN(1,MAX(ROUT(I+1),-1))
IF CHANNEL=1 THEN
LET DAT$(8*I+1:8*I+8)=PACKDBL$(LOUT(I+1))
END IF
IF CHANNEL=2 THEN
LET DAT$(16*I+1:16*I+8)=PACKDBL$(LOUT(I+1))
LET DAT$(16*I+9:16*I+16)=PACKDBL$(ROUT(I+1))
END IF
NEXT I
LET ERR=WRITERF64_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT$)
IF ERR>0 THEN PRINT "書き込みエラー"
FUNCTION WRITERF64_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT$)
OPTION CHARACTER BYTE
ASSIGN ".\DLL\writesnd.dll","writerf64"
END FUNCTION
END SUB
EXTERNAL SUB WRITERAW(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,LOUT(),ROUT())
OPTION CHARACTER BYTE
IF F$="" THEN EXIT SUB
IF NUM=0 THEN LET NUM=UBOUND(LOUT,1)
LET DAT$=REPEAT$(" ",8*NUM*CHANNEL)
IF POS(LCASE$(F$),".raw")=0 THEN LET F$=F$&".raw"
FOR I=0 TO NUM-1
LET LOUT(I+1)=MIN(1,MAX(LOUT(I+1),-1))
LET ROUT(I+1)=MIN(1,MAX(ROUT(I+1),-1))
IF CHANNEL=1 THEN
LET DAT$(8*I+1:8*I+8)=PACKDBL$(LOUT(I+1))
END IF
IF CHANNEL=2 THEN
LET DAT$(16*I+1:16*I+8)=PACKDBL$(LOUT(I+1))
LET DAT$(16*I+9:16*I+16)=PACKDBL$(ROUT(I+1))
END IF
NEXT I
LET ERR=WRITERAW_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT$)
IF ERR>0 THEN PRINT "書き込みエラー"
FUNCTION WRITERAW_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT$)
OPTION CHARACTER BYTE
ASSIGN ".\DLL\writesnd.dll","writeraw"
END FUNCTION
END SUB
-----------------------------------------------------------------------------------------
writesnd.c
#include "sndfile.h"
__declspec(dllexport) int writewav(char *filename,int num,int channel,int samplingfreq,int samplebit,double *data)
{
SNDFILE *sfr;
SF_INFO sfinfo;
int format;
memset (&sfinfo, 0, sizeof (sfinfo)) ;
sfinfo.samplerate=samplingfreq;
sfinfo.channels=channel;
sfinfo.frames=num;
format=SF_FORMAT_PCM_16;
if(samplebit==16) format=SF_FORMAT_PCM_16;
if(samplebit==24) format=SF_FORMAT_PCM_24;
if(samplebit==32) format=SF_FORMAT_PCM_32;
if(samplebit==33) format=SF_FORMAT_FLOAT;
if(samplebit==64) format=SF_FORMAT_DOUBLE;
if(samplebit==4) format=SF_FORMAT_ULAW;
if(samplebit==5) format=SF_FORMAT_ALAW;
if(samplebit==10) format=SF_FORMAT_IMA_ADPCM;
if(samplebit==12) format=SF_FORMAT_MS_ADPCM;
if(samplebit==20) format=SF_FORMAT_GSM610; //samplingfreq=8000Hz時のみ
if(samplebit==30) format=SF_FORMAT_G721_32;
sfinfo.format=(SF_FORMAT_WAV|format);
if(!(sfr = sf_open(filename, SFM_WRITE, &sfinfo))) return 1;
sf_write_double(sfr, data, num*channel);
sf_close(sfr);
return 0;
}
__declspec(dllexport) int writeaiff(char *filename,int num,int channel,int samplingfreq,int samplebit,double *data)
{
SNDFILE *sfr;
SF_INFO sfinfo;
int format;
memset (&sfinfo, 0, sizeof (sfinfo)) ;
sfinfo.samplerate=samplingfreq;
sfinfo.channels=channel;
sfinfo.frames=num;
format=SF_FORMAT_PCM_16;
if(samplebit==8) format=SF_FORMAT_PCM_S8;
if(samplebit==16) format=SF_FORMAT_PCM_16;
if(samplebit==24) format=SF_FORMAT_PCM_24;
if(samplebit==32) format=SF_FORMAT_PCM_32;
sfinfo.format=(SF_FORMAT_AIFF|format);
if(!(sfr = sf_open(filename, SFM_WRITE, &sfinfo))) return 1;
sf_write_double(sfr, data, num*channel);
sf_close(sfr);
return 0;
}
__declspec(dllexport) int writeau(char *filename,int num,int channel,int samplingfreq,int samplebit,double *data)
{
SNDFILE *sfr;
SF_INFO sfinfo;
int format;
sfinfo.samplerate=samplingfreq;
sfinfo.channels=channel;
sfinfo.frames=num;
format=SF_FORMAT_PCM_16;
if(samplebit==8) format=SF_FORMAT_PCM_S8;
if(samplebit==16) format=SF_FORMAT_PCM_16;
if(samplebit==24) format=SF_FORMAT_PCM_24;
if(samplebit==32) format=SF_FORMAT_PCM_32;
sfinfo.format=(SF_FORMAT_AU|format);
if(!(sfr = sf_open(filename, SFM_WRITE, &sfinfo))) return 1;
sf_write_double(sfr, data, num*channel);
sf_close(sfr);
return 0;
}
__declspec(dllexport) int writeflac(char *filename,int num,int channel,int samplingfreq,int samplebit,double *data)
{
SNDFILE *sfr;
SF_INFO sfinfo;
int format;
memset (&sfinfo, 0, sizeof (sfinfo)) ;
sfinfo.samplerate=samplingfreq;
sfinfo.channels=channel;
sfinfo.frames=num;
format=SF_FORMAT_PCM_16;
if(samplebit==8) format=SF_FORMAT_PCM_S8;
if(samplebit==16) format=SF_FORMAT_PCM_16;
if(samplebit==24) format=SF_FORMAT_PCM_24;
sfinfo.format=(SF_FORMAT_FLAC|format);
if(!(sfr = sf_open(filename, SFM_WRITE, &sfinfo))) return 1;
sf_write_double(sfr, data, num*channel);
sf_close(sfr);
return 0;
}
__declspec(dllexport) int writecaf(char *filename,int num,int channel,int samplingfreq,int samplebit,double *data)
{
SNDFILE *sfr;
SF_INFO sfinfo;
int format;
memset (&sfinfo, 0, sizeof (sfinfo)) ;
sfinfo.samplerate=samplingfreq;
sfinfo.channels=channel;
sfinfo.frames=num;
format=SF_FORMAT_PCM_16;
if(samplebit==8) format=SF_FORMAT_PCM_S8;
if(samplebit==16) format=SF_FORMAT_PCM_16;
if(samplebit==24) format=SF_FORMAT_PCM_24;
if(samplebit==32) format=SF_FORMAT_PCM_32;
sfinfo.format=(SF_FORMAT_CAF|format);
if(!(sfr = sf_open(filename, SFM_WRITE, &sfinfo))) return 1;
sf_write_double(sfr, data, num*channel);
sf_close(sfr);
return 0;
}
__declspec(dllexport) int writerf64(char *filename,int num,int channel,int samplingfreq,int samplebit,double *data)
{
SNDFILE *sfr;
SF_INFO sfinfo;
int format;
memset (&sfinfo, 0, sizeof (sfinfo)) ;
sfinfo.samplerate=samplingfreq;
sfinfo.channels=channel;
sfinfo.frames=num;
format=SF_FORMAT_PCM_16;
if(samplebit==16) format=SF_FORMAT_PCM_16;
if(samplebit==24) format=SF_FORMAT_PCM_24;
if(samplebit==32) format=SF_FORMAT_PCM_32;
sfinfo.format=(SF_FORMAT_RF64|format);
if(!(sfr = sf_open(filename, SFM_WRITE, &sfinfo))) return 1;
sf_write_double(sfr, data, num*channel);
sf_close(sfr);
return 0;
}
__declspec(dllexport) int writeraw(char *filename,int num,int channel,int samplingfreq,int samplebit,double *data)
{
SNDFILE *sfr;
SF_INFO sfinfo;
int format;
memset (&sfinfo, 0, sizeof (sfinfo)) ;
sfinfo.samplerate=samplingfreq;
sfinfo.channels=channel;
sfinfo.frames=num;
format=SF_FORMAT_PCM_16;
if(samplebit==8) format=SF_FORMAT_PCM_S8;
if(samplebit==16) format=SF_FORMAT_PCM_16;
if(samplebit==24) format=SF_FORMAT_PCM_24;
if(samplebit==32) format=SF_FORMAT_PCM_32;
sfinfo.format=(SF_FORMAT_RAW|format);
if(!(sfr = sf_open(filename, SFM_WRITE, &sfinfo))) return 1;
sf_write_double(sfr, data, num*channel);
sf_close(sfr);
return 0;
}
Re: wavファイル書き出しルーチン - しばっち
2024/10/13 (Sun) 07:06:15
C/C++ライブラリーによるDLL版の書き込みルーチンです。32bit版のみです。
https://github.com/adamstark/AudioFile
ヘッダーライブラリーです。ヘッダーファイルをインクルードするだけで使えます。
上記URLからダウンロードしてVC++2022で下記cppソースからコンパイルできます。
データ値は-1~1までの値です。
マルチチャンネル書き込み対応のため一部仕様を変更しています。
拡張フォーマットには対応していないようです。
VC++2022でコンパイルしました。
EXTERNAL SUB WRITEWAVMULTI(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT(,))
OPTION CHARACTER BYTE
IF F$="" THEN EXIT SUB
IF NUM=0 THEN LET NUM=UBOUND(DAT,2)
LET DAT$=REPEAT$(" ",8*NUM*CHANNEL)
IF POS(LCASE$(F$),".wav")=0 THEN LET F$=F$&".wav"
IF POS("8 16 24 32",STR$(SAMPLEBIT))=0 THEN LET SAMPLEBIT=16
FOR I=0 TO NUM-1
FOR CH=0 TO CHANNEL-1
LET DAT(CH+1,I+1)=MIN(1,MAX(DAT(CH+1,I+1),-1))
LET DAT$(8*CHANNEL*I+8*CH+1:8*I*CHANNEL+8*CH+8)=PACKDBL$(DAT(CH+1,I+1))
NEXT CH
NEXT I
LET ERR=WRITEWAVMULTI_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT$)
IF ERR>0 THEN PRINT "書き込みエラー"
FUNCTION WRITEWAVMULTI_(F$,NUM,CHANNEL,SAMPLINGFREQ,SAMPLEBIT,DAT$)
OPTION CHARACTER BYTE
ASSIGN ".\DLL\writewavmulti.dll","writewavmulti"
END FUNCTION
END SUB
-----------------------------------------------------------------------------------------
writewavmulti.cpp
#include "AudioFile.h"
using namespace std;
extern "C" __declspec(dllexport) int writewavmulti(char *name,int num,int channel,int samplingfreq,int samplebit,double *dat)
{
AudioFile<double> audioFile;
audioFile.setAudioBufferSize (channel, num);
audioFile.setBitDepth (samplebit);
audioFile.setSampleRate (samplingfreq);
for (int i = 0; i < num; i++)
for (int ch = 0; ch < channel; ch++)
audioFile.samples[ch][i]=dat[i*channel+ch];
if(audioFile.save(name, AudioFileFormat::Wave)) return 0;
else return 1;
}
-----------------------------------------------------------------------------------------
使用例
LET SAMPLINGFREQ=44100
LET NUM=SAMPLINGFREQ*3
LET CHANNEL=2
DIM DAT(CHANNEL,NUM)
FOR I=1 TO NUM
FOR CH=1 TO CHANNEL
LET DAT(CH,I)=SIN(440*CH/SAMPLINGFREQ*I*2*PI)*.5
NEXT CH
NEXT I
CALL WRITEWAVMULTI("sample.wav",NUM,1,SAMPLINGFREQ,16,DAT)
END
Re: wavファイル書き出しルーチン - しばっち
2024/10/13 (Sun) 07:07:24
C/C++ライブラリーによる再生ルーチンです。32bit版のみです。
https://solhsa.com/soloud/index.html
※再生中の途中停止はできません。タスクマネージャーからの強制終了しかありません。
くれぐれも気を付けてください。
VC++2022でコンパイルしました。
FILE GETOPENNAME F$,"読み込み WAV,MP3,OGG,FLACファイル|*.WAV;*.MP3;*.OGG;*.FLAC"
IF F$="" THEN STOP
CALL AUDIOPLAY(F$)
END
EXTERNAL SUB AUDIOPLAY(F$)
LET VOL$=REPEAT$(" ",8)
LET VOL$(1:8)=PACKDBL$(.6) ! ボリューム(0~1)
CALL AUDIOPLAY_(F$,VOL$)
SUB AUDIOPLAY_(F$,VOL$)
ASSIGN ".\DLL\audioplay.dll","audioplay"
END SUB
END SUB
----------------------------------------------------------------
audioplay.cpp
#include "soloud.h"
#include "soloud_wav.h"
#include "soloud_thread.h"
using namespace std;
extern "C" __declspec(dllexport) void audioplay(char *name,double *vol)
{
SoLoud::Soloud soloud;
SoLoud::Wav wav;
soloud.init();
wav.load(name);
wav.setVolume((float)*vol);
soloud.play(wav);
while (soloud.getActiveVoiceCount() > 0)
SoLoud::Thread::sleep(100);
wav.stop();
soloud.deinit();
}
----------------------------------------------------------------
C/C++ライブラリーによる再生ルーチンです。32bit版のみです。
ファイルに書き出すのではなく、サウンドデバイスにPCMデータを送って再生します。
※再生中の途中停止はできません。
VC++2022でコンパイルしました。
LET SAMPLINGFREQ=44100
LET NUM=SAMPLINGFREQ*3
LET CHANNEL=1
DIM LOUT(NUM),ROUT(NUM)
FOR I=1 TO NUM
LET LOUT(I)=SIN(400/SAMPLINGFREQ*I*2*PI)*.4
! LET ROUT(I)=SIN(403/SAMPLINGFREQ*I*2*PI)*.4
NEXT I
CALL PCMPLAY(NUM,CHANNEL,SAMPLINGFREQ,LOUT,ROUT)
END
EXTERNAL SUB PCMPLAY(NUM,CHANNEL,SAMPLINGFREQ,LOUT(),ROUT())
OPTION CHARACTER BYTE
IF NUM=0 THEN LET NUM=UBOUND(LOUT,1)
LET LOUT$=REPEAT$(" ",8*NUM)
LET ROUT$=REPEAT$(" ",8*NUM)
LET VOL$=REPEAT$(" ",8)
LET VOL$(1:8)=PACKDBL$(.6) ! ボリューム(0~1)
FOR I=0 TO NUM-1
LET LOUT(I+1)=MIN(1,MAX(LOUT(I+1),-1))
LET LOUT$(8*I+1:8*I+8)=PACKDBL$(LOUT(I+1))
IF CHANNEL=2 THEN
LET ROUT(I+1)=MIN(1,MAX(ROUT(I+1),-1))
LET ROUT$(8*I+1:8*I+8)=PACKDBL$(ROUT(I+1))
END IF
NEXT I
CALL PCMPLAY_(NUM,CHANNEL,SAMPLINGFREQ,LOUT$,ROUT$,VOL$)
SUB PCMPLAY_(NUM,CHANNEL,SAMPLINGFREQ,LOUT$,ROUT$,VOL$)
ASSIGN ".\DLL\pcmplay.dll","pcmplay"
END SUB
END SUB
----------------------------------------------------------------
pcmplay.cpp
#include "soloud.h"
#include "soloud_wav.h"
#include "soloud_thread.h"
using namespace std;
extern "C" __declspec(dllexport) void pcmplay(int num,int channel,int samplingfreq,double *lin,double *rin,double *vol)
{
SoLoud::Soloud soloud;
SoLoud::Wav gwave;
float *buf;
int i;
buf=new float [num*channel];
soloud.init();
for(i=0; i<num; i++) {
if(channel==1) buf[i]=(float)lin[i];
else if(channel==2) {
buf[2*i]=(float)lin[i];
buf[2*i+1]=(float)rin[i];
}
}
gwave.loadRawWave(buf,num*channel,samplingfreq,channel,true,true);
gwave.setVolume(*vol);
soloud.play(gwave);
while (soloud.getActiveVoiceCount() > 0)
SoLoud::Thread::sleep(100);
gwave.stop();
delete [] buf;
soloud.deinit();
}
----------------------------------------------------------------
おまけ。
C/C++ライブラリーによる機械音声出力します。
日本語の発声はできません。
※再生中の途中停止はできません。
VC++2022でコンパイルしました。
LET WORD$="Let's enjoy sound programming!"
!INPUT PROMPT "MESSAGE=":WORD$
!IF WORD$="" THEN STOP
CALL SPEECH(WORD$) ! 英語 only
END
EXTERNAL SUB SPEECH(WORD$)
ASSIGN ".\DLL\speech.dll","speech"
END SUB
----------------------------------------------------------------
speech.cpp
#include "soloud.h"
#include "soloud_speech.h"
#include "soloud_thread.h"
using namespace std;
extern "C" __declspec(dllexport) void speech(char *word)
{
SoLoud::Soloud soloud;
SoLoud::Speech speech;
speech.setText(word);
soloud.init();
soloud.play(speech);
while (soloud.getActiveVoiceCount() > 0)
SoLoud::Thread::sleep(100);
soloud.deinit();
}
DATA文 Ver. 7.8.6.8での変更 - 白石和夫 URL
2024/09/27 (Fri) 21:14:22
Ver. 7.8.6.8でDATA文に漢字を含む文字列を書くとき引用符で括ることを必須化しましたが,同梱サンプルの修正が漏れていました。
SAMPLE\KEPLER3.BASを下記のように書き換えてください。
なお,ver.8.1.2.6,Ver.0.7.4.1でも同様です。
REM 両対数グラフ
REM 軌道半径, 公転周期(地球を1とする)
DATA 0.39, 0.241 ,"水星"
DATA 0.72, 0.615 ,"金星"
DATA 1 , 1 ,"地球"
DATA 1.52, 1.88 ,"火星"
DATA 5.20, 11.86 ,"木星"
DATA 9.55, 29.46 ,"土星"
DATA 19.2 , 84.01 ,"天王星"
DATA 30.1 , 164.8 ,"海王星"
SET WINDOW -1,3,-1,3
SET LINE COLOR 15
SET TEXT COLOR 15
FOR n=-1 TO 2
FOR a=1 TO 9
LET x=a*10^n
PLOT LINES : LOG10(x),-1; LOG10(x),3
NEXT a
PLOT TEXT , AT n,-1: STR$(10^n)
NEXT n
FOR m=-1 TO 3
FOR b=1 TO 9
LET y=b*10^m
PLOT LINES : -1,LOG10(y);3,LOG10(y)
NEXT b
PLOT TEXT , AT -1, m:STR$(10^m)
NEXT m
SET TEXT COLOR 1
SET TEXT JUSTIFY "left","top"
DO
READ IF MISSING THEN EXIT DO: x,y,s$
LET a=LOG10(x)
LET b=LOG10(y)
PLOT POINTS: a, b
PLOT TEXT ,AT a,b: s$
LOOP
END
GPIOからのアナログ値 - 加藤進
2024/08/21 (Wed) 19:44:43
ご指摘ありがとうございます。データが1行で送られてくるようです。Tera Termでも動作が確認できます。添付はGPIO-08です。
GPIOからのアナログ値 - 加藤 進
2024/07/31 (Wed) 13:59:29
BASICにGPIOのアダプターをつけてCOM経由でやっとのことでLEDのON/OFFができるようになりました。CdSなどの照度センサーからのアナログ値を読み込む命令はどのように作ればいいのでしょうか?現在はアダプターはDevice managerによるとCOM3を利用しています。
2024/07/31 (Wed) 16:36:37
Windows版十進BASICは通常ファイルと同様に仮想COMポートが使えます.
行末は
独自拡張の SET #経路番号 : ENDOFLINE
を実行して通信相手と合わせてください。
https://decimalbasic.web.fc2.com/BASICHelp/html/basi7cit.htm
データをバイナリ値で受信する場合は,
https://decimalbasic.web.fc2.com/QA7-1.htm
を参照してください。
受信はバッファを介して行います。CHARACTER INPUT文で一バイトずつ受信するとき,
ASK #経路番号: CHARACTER PENDING 数値変数
を実行してバッファに受信されているデータのバイト数を知ることができます。
https://decimalbasic.web.fc2.com/BASICHelp/html/basi1yd0.htm
Re: GPIOからのアナログ値 - 加藤進
2024/08/01 (Thu) 19:32:28
お忙しいところのご回答を感謝します。検討したいと思います。なおGPIO-08というNumato Labのアダプターです。
2024/07/24 (Wed) 10:17:52
十進BASICホームページを移転しました。
https://decimalbasic.web.fc2.com/
リンク修正の不備などお気づきの点があればお知らせください。
なお,旧ページは2024年12月20日以降,接続できなくなります。
vitalgraph - gnuutera2012or文句うさびょん URL
2024/07/01 (Mon) 22:06:59
バイタルサインを整理するのに使ってます。
年、月、日、時、分、収縮、拡張、脈拍、体温、SpO2、治療、食事、服薬、排便、歯磨き、備考です。
テキスト表示とグラフ表示。
詳しくはF1ヘルプ画面をご参考に。
DATA "2024","6","22","22","29","137","88" ,"88","37.9"," -- ","2300" ,"2200","2230" ,"0" ,"0" ,"特になし。"
DATA "2024","6","23","09","05","150","91" ,"81","36.3"," -- ","1020" ,"0920","0948" ,"3" ,"0" ,"特になし。"
DATA "2024","6","23","13","44","150","95" ,"78","37.2"," -- "," -- " ,"1330","1340" ,"0" ,"0" ,"特になし。"
DATA "2024","6","23","19","00","157","99" ,"85","37.0"," -- ","2330" ,"1900","1900" ,"0" ,"0" ,"特になし。"
DATA "2024","6","24","10","14","151","94" ,"79","37.5"," -- ","1035" ,"0800","0800" ,"3" ,"0" ,"特になし。"
DATA "2024","6","24","14","00","161","100","79","36.4"," -- "," -- " ,"1338","1340" ,"0" ,"0" ,"特になし。"
DATA "2024","6","24","23","00","158","106","86","37.5"," -- ","2315" ,"2230","2230" ,"0" ,"0" ,"特になし。"
DATA "2024","6","25","08","00","169","105","87","37.3"," -- ","0840" ,"0700","0700" ,"4" ,"0" ,"特になし。"
DATA "2024","6","25","14","10","154","96" ,"89","37.2"," -- "," -- " ,"1300","1300" ,"0" ,"0" ,"特になし。"
DATA "2024","6","25","23","15","170","114","80","37.3"," -- ","2355" ,"2146","2146" ,"0" ,"0" ,"特になし。"
DATA "2024","6","26","08","15","170","109","79","37.3"," -- "," -- " ,"0820"," -- " ,"4" ,"0" ,"特になし。"
DATA "2024","6","26","12","40","180","114","86","37.2"," -- ","1415" ,"1230","1238" ,"7" ,"0" ,"特になし。"
DATA "2024","6","26","19","00","186","116","84","36.9"," -- ","2130" ,"1840","1900" ,"0" ,"0" ,"特になし。"
DATA "2024","6","27","08","48","155","112","78","37.0"," -- ","0913" ,"0900","0930" ,"4" ,"1" ,"特になし。"
DATA "2024","6","27","11","10","161","84" ,"89","37.0"," -- "," -- " ,"1100","1115" ,"0" ,"0" ,"特になし。"
DATA "2024","6","27","21","23","173","120","77","37.4"," -- ","2307" ,"2120","2136" ,"0" ,"1" ,"特になし。"
DATA "2024","6","28","09","38","154","115","77","36.8"," -- ","0932" ,"0944","0950" ,"4" ,"0" ,"特になし。"
DATA "2024","6","28","12","30","177","107","92","36.4"," -- "," -- " ,"1230","1235" ,"4" ,"0" ,"特になし。"
DATA "2024","6","28","23","35","172","109","85","37.4"," -- ","2333" ,"2330","2347" ,"0" ,"0" ,"特になし。"
DATA "2024","6","29","06","51","152","111","83","37.3"," -- ","0700" ,"0650","0655" ,"4" ,"1" ,"特になし。"
DATA "2024","6","29","13","25","173","118","87","37.6"," -- "," -- " ,"1310","1325" ,"3" ,"1" ,"特になし。"
DATA "2024","6","29","20","35","169","102","92","36.9"," -- ","2117" ,"2030","2032" ,"0" ,"0" ,"特になし。"
DATA "2024","6","30","08","03","170","107","79","37.4"," -- ","0815" ,"0800","0800" ,"0" ,"1" ,"特になし。"
DATA "2024","6","30","12","23","171","110","82","37.3"," -- "," -- " ,"1220","1230" ,"4" ,"1" ,"特になし。"
DATA "2024","6","30","17","55","159","111","79","37.4"," -- ","1828" ,"1800","1810" ,"0" ,"0" ,"特になし。"
DATA "2024","7","01","06","45","171","122","82","36.6"," -- "," -- " ,"0645","0745" ,"4" ,"0" ,"特になし。"
DATA "2024","7","01","12","10","170","111","84","37.5","97" ,"1240" ,"1225","1240" ,"0" ,"1" ,"特になし。"
DATA "2024","7","01","20","45","172","106","85","37.5","96" ," " ,"2045","2100" ,"0" ,"1" ,"特になし。"
DIM YRS$(100),MOS$(100),DYS$(100),HUR$(100),MNT$(100),SYS$(100),DIA$(100),PUL$(100),TEM$(100),SPO$(100),TRE$(100),FOD$(100),CAL$(100),DEF$(100),DEN$(100),CMM$(100)
FOR I=1 TO 100
READ IF MISSING THEN EXIT FOR : YRS$(I),MOS$(I),DYS$(I),HUR$(I),MNT$(I),SYS$(I),DIA$(I),PUL$(I),TEM$(I),SPO$(I),TRE$(I),FOD$(I),CAL$(I),DEF$(I),DEN$(I),CMM$(I)
NEXT I
LET NUM=I-1
PRINT USING "## ":"年";
PRINT ",";
PRINT USING "##":"月";
PRINT ",";
PRINT USING "##":"日";
PRINT ",";
PRINT USING "##":"時";
PRINT ",";
PRINT USING "##":"分";
PRINT ",";
PRINT USING "####":"収縮";
PRINT ",";
PRINT USING "####":"拡張";
PRINT ",";
PRINT USING "####":"脈拍";
PRINT ",";
PRINT USING "####":"体温";
PRINT ",";
PRINT USING "####":"SpO2";
PRINT ",";
PRINT USING ">######":"治療";
PRINT ",";
PRINT USING "####":"食事";
PRINT ",";
PRINT USING "####":"服薬";
PRINT ",";
PRINT USING "####":"排便";
PRINT ",";
PRINT USING "######":"歯磨き";
PRINT ",";
PRINT USING "####":"備考"
FOR I=1 TO NUM
PRINT USING ">###" :YRS$(I);
PRINT ",";
PRINT USING ">#" :MOS$(I);
PRINT ",";
PRINT USING ">#" :DYS$(I);
PRINT ",";
PRINT USING ">#" :HUR$(I);
PRINT ",";
PRINT USING ">#" :MNT$(I);
PRINT ",";
PRINT USING ">###" :SYS$(I);
PRINT ",";
PRINT USING ">###" :DIA$(I);
PRINT ",";
PRINT USING ">###" :PUL$(I);
PRINT ",";
PRINT USING ">#.#" :TEM$(I);
PRINT ",";
PRINT USING ">###" :SPO$(I);
PRINT ",";
PRINT USING " >###" :TRE$(I);
PRINT ",";
PRINT USING ">###" :FOD$(I);
PRINT ",";
PRINT USING ">###" :CAL$(I);
PRINT ",";
PRINT USING ">###" :DEF$(I);
PRINT ",";
PRINT USING ">#####" :DEN$(I);
PRINT ",";
PRINT USING "<#######################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################" :CMM$(I)
NEXT I
FOR I=1 TO NUM
IF CAL$(I)<>" -- " THEN LET DOSE_OF_CALONAL_A=DOSE_OF_CALONAL_A+1
NEXT I
PRINT USING "CALONAL A 累積使用数 >###錠" : DOSE_OF_CALONAL_A
REM _/_/_/【体温】_/_/_/
SET VIEWPORT 0,0.5, 0.5,1
REM 一日目から36℃~42℃の範囲でデータを描画する。
SET WINDOW 1,NUM+1,36,43
DRAW GRID(1,0.1)
REM 体温のグリッドを描画する。
SET LINE COLOR 1
SET LINE STYLE 3
FOR I=1 TO (42-36)/1
PLOT LINES: 1, 36+I; NUM, 36+I
NEXT I
SET LINE STYLE 1
REM 体温の軸の目盛りを描画する。
FOR I=1 TO (42-36)/0.5
PLOT TEXT ,AT 1, 36+I*0.5: STR$(36+I*0.5)
NEXT I
FOR I=1 TO (42-36)/0.5
PLOT TEXT ,AT NUM-2, 36+I*0.5: STR$(36+I*0.5)
NEXT I
REM 体温の折れ線グラフを描画する。
PLOT TEXT ,AT 2, 42: "体温"
FOR I=1 TO NUM
SET LINE COLOR 4
SET LINE WIDTH 3
SET POINT STYLE 6
SET POINT COLOR 4
REM (1-1)I<NUM、かつ、I番目は欠損値ではない、かつ、I+1番目は欠損値ではない。
IF I<NUM AND TEM$(I)<>" -- " AND TEM$(I+1)<>" -- " THEN PLOT LINES : I,VAL(TEM$(I));I+1,VAL(TEM$(I+1))
PLOT LINES
REM (1-2)I<NUM、かつ、I番目は欠損値ではない、かつ、I+1番目は欠損値。
IF I<NUM AND TEM$(I)<>" -- " AND TEM$(I+1)= " -- " THEN PLOT POINTS : I,VAL(TEM$(I))
! REM (1-3)I<NUM、かつ、I番目が欠損値。 ! → I+1番目が欠損値の場合は、次のNEXT Iで対応しているので、すでにI+1番目が欠損値の場合も含まれていることに注意。
! FOR J=1 TO (42-36)/0.01
! IF I<NUM AND TEM$(I)= " -- " THEN PLOT POINTS : I,36+J*0.01
! NEXT J
REM (2-1)I=NUM、かつ、I番目は欠損値ではない。
IF I=NUM AND TEM$(I)<>" -- " THEN PLOT POINTS : I,VAL(TEM$(I))
! REM (2-2)I=NUM、かつ、I番目は欠損値。
! FOR J=1 TO (42-36)/0.01
! IF I=NUM AND TEM$(I)= " -- " THEN PLOT POINTS : I,36+J*0.01
! NEXT J
NEXT I
PLOT LINES
SET POINT STYLE 1
REM 日付と時刻を描画する。
FOR I=1 TO NUM
PLOT TEXT ,AT I, 36.36: MOS$(I)
PLOT TEXT ,AT I, 36.24: DYS$(I)
PLOT TEXT ,AT I, 36.12: HUR$(I)
PLOT TEXT ,AT I, 36 : MNT$(I)
NEXT I
SET LINE WIDTH 1
SET POINT STYLE 1
REM _/_/_/【血圧】【脈拍】【歯磨き】_/_/_/
SET VIEWPORT 0.5,1, 0.5,1
REM 一日目から65mmHg~195mmHg、65cycle/min~195cycle/minの範囲でデータを描画する。
SET WINDOW 1,NUM+1,65,195
DRAW GRID(1,1)
REM 収縮期血圧、拡張期血圧、脈拍のグリッドを描画する。
SET LINE COLOR 1
SET LINE STYLE 3
FOR I=1 TO (190-70)/5
PLOT LINES: 1, 70+I*5; NUM, 70+I*5
NEXT I
SET LINE STYLE 1
REM 収縮期血圧、拡張期血圧、脈拍の軸の目盛りを描画する。
FOR I=1 TO (190-70)/5
PLOT TEXT ,AT 1, 70+I*5: STR$(70+I*5)
NEXT I
FOR I=1 TO (190-70)/5
PLOT TEXT ,AT NUM-2, 70+I*5: STR$(70+I*5)
NEXT I
REM 収縮期血圧の折れ線グラフを描画する。
PLOT TEXT ,AT 2, 150: "収縮期血圧"
FOR I=1 TO NUM
SET LINE COLOR 4
SET LINE WIDTH 3
SET POINT STYLE 6
SET POINT COLOR 4
REM (1-1)I<NUM、かつ、I番目は欠損値ではない、かつ、I+1番目は欠損値ではない。
IF I<NUM AND SYS$(I)<>" -- " AND SYS$(I+1)<>" -- " THEN PLOT LINES : I,VAL(SYS$(I));I+1,VAL(SYS$(I+1))
PLOT LINES
REM (1-2)I<NUM、かつ、I番目は欠損値ではない、かつ、I+1番目は欠損値。
IF I<NUM AND SYS$(I)<>" -- " AND SYS$(I+1)= " -- " THEN PLOT POINTS : I,VAL(SYS$(I))
! REM (1-3)I<NUM、かつ、I番目が欠損値。 ! → I+1番目が欠損値の場合は、次のNEXT Iで対応しているので、すでにI+1番目が欠損値の場合も含まれていることに注意。
! FOR J=1 TO (190-70)/0.5
! IF I<NUM AND SYS$(I)= " -- " THEN PLOT POINTS : I,70+J*0.5
! NEXT J
REM (2-1)I=NUM、かつ、I番目は欠損値ではない。
IF I=NUM AND SYS$(I)<>" -- " THEN PLOT POINTS : I,VAL(SYS$(I))
! REM (2-2)I=NUM、かつ、I番目は欠損値。
! FOR J=1 TO (190-70)/0.5
! IF I=NUM AND SYS$(I)= " -- " THEN PLOT POINTS : I,70+J*0.5
! NEXT J
NEXT I
PLOT LINES
REM 拡張期血圧の折れ線グラフを描画する。
PLOT TEXT ,AT 2, 90 : "拡張期血圧"
FOR I=1 TO NUM
SET LINE COLOR 2
SET LINE WIDTH 3
SET POINT STYLE 6
SET POINT COLOR 2
REM (1-1)I<NUM、かつ、I番目は欠損値ではない、かつ、I+1番目は欠損値ではない。
IF I<NUM AND DIA$(I)<>" -- " AND DIA$(I+1)<>" -- " THEN PLOT LINES : I,VAL(DIA$(I));I+1,VAL(DIA$(I+1))
PLOT LINES
REM (1-2)I<NUM、かつ、I番目は欠損値ではない、かつ、I+1番目は欠損値。
IF I<NUM AND DIA$(I)<>" -- " AND DIA$(I+1)= " -- " THEN PLOT POINTS : I,VAL(DIA$(I))
! REM (1-3)I<NUM、かつ、I番目が欠損値。 ! → I+1番目が欠損値の場合は、次のNEXT Iで対応しているので、すでにI+1番目が欠損値の場合も含まれていることに注意。
! FOR J=1 TO (190-70)/0.5
! IF I<NUM AND DIA$(I)= " -- " THEN PLOT POINTS : I,70+J*0.5
! NEXT J
REM (2-1)I=NUM、かつ、I番目は欠損値ではない。
IF I=NUM AND DIA$(I)<>" -- " THEN PLOT POINTS : I,VAL(DIA$(I))
! REM (2-2)I=NUM、かつ、I番目は欠損値。
! FOR J=1 TO (190-70)/0.5
! IF I=NUM AND DIA$(I)= " -- " THEN PLOT POINTS : I,70+J*0.5
! NEXT J
NEXT I
PLOT LINES
REM 脈拍の折れ線グラフを描画する。
PLOT TEXT ,AT 2, 80 : "脈拍"
FOR I=1 TO NUM
SET LINE COLOR 7
SET LINE WIDTH 3
SET POINT STYLE 6
SET POINT COLOR 7
REM (1-1)I<NUM、かつ、I番目は欠損値ではない、かつ、I+1番目は欠損値ではない。
IF I<NUM AND PUL$(I)<>" -- " AND PUL$(I+1)<>" -- " THEN PLOT LINES : I,VAL(PUL$(I));I+1,VAL(PUL$(I+1))
PLOT LINES
REM (1-2)I<NUM、かつ、I番目は欠損値ではない、かつ、I+1番目は欠損値。
IF I<NUM AND PUL$(I)<>" -- " AND PUL$(I+1)= " -- " THEN PLOT POINTS : I,VAL(PUL$(I))
! REM (1-3)I<NUM、かつ、I番目が欠損値。 ! → I+1番目が欠損値の場合は、次のNEXT Iで対応しているので、すでにI+1番目が欠損値の場合も含まれていることに注意。
! FOR J=1 TO (190-70)/0.5
! IF I<NUM AND PUL$(I)= " -- " THEN PLOT POINTS : I,70+J*0.5
! NEXT J
REM (2-1)I=NUM、かつ、I番目は欠損値ではない。
IF I=NUM AND PUL$(I)<>" -- " THEN PLOT POINTS : I,VAL(PUL$(I))
! REM (2-2)I=NUM、かつ、I番目は欠損値。
! FOR J=1 TO (190-70)/0.5
! IF I=NUM AND PUL$(I)= " -- " THEN PLOT POINTS : I,70+J*0.5
! NEXT J
NEXT I
PLOT LINES
REM 歯磨きの折れ線グラフを描画する。
PLOT TEXT ,AT 2, 120: "歯磨き"
FOR I=1 TO NUM
SET LINE COLOR 14
SET LINE WIDTH 3
SET POINT STYLE 6
SET POINT COLOR 14
REM (1-1)I<NUM、かつ、I番目は欠損値ではない、かつ、I+1番目は欠損値ではない。
IF I<NUM AND DEN$(I)<>" -- " AND DEN$(I+1)<>" -- " THEN PLOT LINES : I,120+10*VAL(DEN$(I));I+1,120+10*VAL(DEN$(I+1))
PLOT LINES
REM (1-2)I<NUM、かつ、I番目は欠損値ではない、かつ、I+1番目は欠損値。
IF I<NUM AND DEN$(I)<>" -- " AND DEN$(I+1)= " -- " THEN PLOT POINTS : I,120+10*VAL(DEN$(I))
! REM (1-3)I<NUM、かつ、I番目が欠損値。 ! → I+1番目が欠損値の場合は、次のNEXT Iで対応しているので、すでにI+1番目が欠損値の場合も含まれていることに注意。
! FOR J=1 TO (190-70)/0.5
! IF I<NUM AND DEN$(I)= " -- " THEN PLOT POINTS : I,70+J*0.5
! NEXT J
REM (2-1)I=NUM、かつ、I番目は欠損値ではない。
IF I=NUM AND DEN$(I)<>" -- " THEN PLOT POINTS : I,120+10*VAL(DEN$(I))
! REM (2-2)I=NUM、かつ、I番目は欠損値。
! FOR J=1 TO (190-70)/0.5
! IF I=NUM AND DEN$(I)= " -- " THEN PLOT POINTS : I,70+J*0.5
! NEXT J
NEXT I
PLOT LINES
REM 日付と時刻を描画する。
FOR I=1 TO NUM
PLOT TEXT ,AT I, 72.5: MOS$(I)
PLOT TEXT ,AT I, 70 : DYS$(I)
PLOT TEXT ,AT I, 67.5: HUR$(I)
PLOT TEXT ,AT I, 65 : MNT$(I)
NEXT I
PLOT LINES
SET LINE WIDTH 1
SET POINT STYLE 1
REM _/_/_/【SPO2】_/_/_/
SET VIEWPORT 0,0.5, 0,0.5
REM 一日目から69~101の範囲でデータを描画する。
SET WINDOW 1,NUM+1,69,101
DRAW GRID(1,1)
REM SPO2のグリッドを描画する。
SET LINE COLOR 1
SET LINE STYLE 3
FOR I=1 TO (100-70)/10
PLOT LINES: 1, 70+I*10; NUM, 70+I*10
NEXT I
SET LINE STYLE 1
REM SPO2の軸の目盛りを描画する。
FOR I=1 TO (100-70)/5
PLOT TEXT ,AT 1, 70+I*5: STR$(70+I*5)
NEXT I
FOR I=1 TO (100-70)/5
PLOT TEXT ,AT NUM-2, 70+I*5: STR$(70+I*5)
NEXT I
REM SPO2の折れ線グラフを描画する。
PLOT TEXT ,AT 2, 100: "SPO2"
FOR I=1 TO NUM
SET LINE COLOR 9
SET LINE WIDTH 3
SET POINT STYLE 6
SET POINT COLOR 9
REM (1-1)I<NUM、かつ、I番目は欠損値ではない、かつ、I+1番目は欠損値ではない。
IF I<NUM AND SPO$(I)<>" -- " AND SPO$(I+1)<>" -- " THEN PLOT LINES : I,VAL(SPO$(I));I+1,VAL(SPO$(I+1))
PLOT LINES
REM (1-2)I<NUM、かつ、I番目は欠損値ではない、かつ、I+1番目は欠損値。
IF I<NUM AND SPO$(I)<>" -- " AND SPO$(I+1)= " -- " THEN PLOT POINTS : I,VAL(SPO$(I))
! REM (1-3)I<NUM、かつ、I番目が欠損値。 ! → I+1番目が欠損値の場合は、次のNEXT Iで対応しているので、すでにI+1番目が欠損値の場合も含まれていることに注意。
! FOR J=1 TO (100-70)/0.5
! IF I<NUM AND SPO$(I)= " -- " THEN PLOT POINTS : I,70+J*0.5
! NEXT J
REM (2-1)I=NUM、かつ、I番目は欠損値ではない。
IF I=NUM AND SPO$(I)<>" -- " THEN PLOT POINTS : I,VAL(SPO$(I))
! REM (2-2)I=NUM、かつ、I番目は欠損値。
! FOR J=1 TO (100-70)/0.5
! IF I=NUM AND SPO$(I)= " -- " THEN PLOT POINTS : I,70+J*0.5
! NEXT J
NEXT I
! こういう方法もある。
! REM SPO2の折れ線グラフを描画する。
! FOR I=1 TO NUM
! SET LINE COLOR 9
! SET LINE WIDTH 2
! SET POINT STYLE 6
! SET POINT COLOR 9
! REM (1-1)
! IF I<NUM AND SPO$(I)<>" -- " AND SPO$(I+1)<>" -- " THEN PLOT LINES: I,VAL(SPO$(I));I+1,VAL(SPO$(I+1))
! PLOT LINES
! REM (1-2)
! IF I<NUM AND SPO$(I)<>" -- " AND SPO$(I+1)=" -- " THEN PLOT LINES: I-0.07,VAL(SPO$(I));I,VAL(SPO$(I))-0.07;I+0.07,VAL(SPO$(I));I,VAL(SPO$(I))+0.07;I-0.07,VAL(SPO$(I))
! PLOT LINES
! REM (1-3)
! IF I<NUM AND SPO$(I)=" -- " THEN PLOT LINES: I,70;I,100
! PLOT LINES
! REM (2-1)
! IF I=NUM AND SPO$(I)<>" -- " THEN PLOT LINES: I-0.07,VAL(SPO$(I));I,VAL(SPO$(I))-0.07;I+0.07,VAL(SPO$(I));I,VAL(SPO$(I))+0.07;I-0.07,VAL(SPO$(I))
! PLOT LINES
! REM (2-2)
! IF I=NUM AND SPO$(I)=" -- " THEN PLOT LINES: I,70;I,100
! PLOT LINES
! NEXT I
! PLOT LINES
! SET POINT STYLE 1
PLOT LINES
REM 日付と時刻を描画する。
FOR I=1 TO NUM
PLOT TEXT ,AT I, 71.8: MOS$(I)
PLOT TEXT ,AT I, 71.2: DYS$(I)
PLOT TEXT ,AT I, 70.6: HUR$(I)
PLOT TEXT ,AT I, 70 : MNT$(I)
NEXT I
SET LINE WIDTH 1
SET POINT STYLE 1
REM _/_/_/【排便】_/_/_/
SET VIEWPORT 0.5,1, 0,0.5
REM 一日目から-1~7.5の範囲でデータを描画する。
SET WINDOW 1,NUM+1,-1,7.5
DRAW GRID(1,1)
REM 排便のグリッドを描画する。
SET LINE COLOR 1
SET LINE STYLE 3
FOR I=1 TO (7-0)/1
PLOT LINES: 1, 0+I; NUM, 0+I
NEXT I
SET LINE STYLE 1
REM 排便の軸の目盛りを描画する。
FOR I=1 TO (7-0)/1
PLOT TEXT ,AT 1, 0+I*1: STR$(0+I*1)
NEXT I
FOR I=1 TO (7-0)/1
PLOT TEXT ,AT NUM-2, 0+I*1: STR$(0+I*1)
NEXT I
REM 排便の折れ線グラフを描画する。
PLOT TEXT ,AT 2, 7: "排便"
FOR I=1 TO NUM
SET LINE COLOR 1
SET LINE WIDTH 3
SET POINT STYLE 6
SET POINT COLOR 1
REM (1-1)I<NUM、かつ、I番目は欠損値ではない、かつ、I+1番目は欠損値ではない。
IF I<NUM AND DEF$(I)<>" -- " AND DEF$(I+1)<>" -- " THEN PLOT LINES : I,VAL(DEF$(I));I+1,VAL(DEF$(I+1))
PLOT LINES
REM (1-2)I<NUM、かつ、I番目は欠損値ではない、かつ、I+1番目は欠損値。
IF I<NUM AND DEF$(I)<>" -- " AND DEF$(I+1)= " -- " THEN PLOT POINTS : I,VAL(DEF$(I))
! REM (1-3)I<NUM、かつ、I番目が欠損値。 ! → I+1番目が欠損値の場合は、次のNEXT Iで対応しているので、すでにI+1番目が欠損値の場合も含まれていることに注意。
! FOR J=1 TO (7-0)/0.01
! IF I<NUM AND DEF$(I)= " -- " THEN PLOT POINTS : I,0+J*0.01
! NEXT J
REM (2-1)I=NUM、かつ、I番目は欠損値ではない。
IF I=NUM AND DEF$(I)<>" -- " THEN PLOT POINTS : I,VAL(DEF$(I))
! REM (2-2)I=NUM、かつ、I番目は欠損値。
! FOR J=1 TO (7-0)/0.01
! IF I=NUM AND DEF$(I)= " -- " THEN PLOT POINTS : I,0+J*0.01
! NEXT J
NEXT I
PLOT LINES
REM 日付と時刻を描画する。
FOR I=1 TO NUM
PLOT TEXT ,AT I, -1+0.8: MOS$(I)
PLOT TEXT ,AT I, -1+0.6: DYS$(I)
PLOT TEXT ,AT I, -1+0.4: HUR$(I)
PLOT TEXT ,AT I, -1+0.2: MNT$(I)
NEXT I
SET LINE WIDTH 1
SET POINT STYLE 1
REM _/_/_/【ヘルプ欄より】_/_/_/
REM BASICの描画命令では色を直接指定するのではなく,色指標という番号を用いて間接的に色を指定する。
REM 色指標に対応する色は固定されていない。色指標は,XYプロッタのペンホルダの番号のようなものである。各色指標には自由に色を割り当てることができる。
REM 色指標0の色は背景色で,特別な意味を持つ。また,各描画命令は,特に指定がない場合には色指標1の色を用いる。
REM 本BASICでは,色指標は0から255までが利用でき,あらかじめ次のように割り当てられている。
REM 0白, 1黒, 2青, 3緑, 4赤, 5水色, 6黄色, 7赤紫,
REM 8 灰色,9 濃い青,10 濃い緑,11 青緑, 12 えび茶,13 オリーブ色,14 濃い紫,15 銀色,・・・
REM SET COLOR MIX(色指標) 数値式,数値式,数値式
REM 色指標に対応する色を変える。色指標は数値式で与える。
REM 3つ並んだ数値式は,赤,緑,青の順に強度を0~1の数値で指定する。
REM 例
REM SET COLOR MIX(1) 0,0,1
REM を実行すると,以後,1番の色が青になる。
END
桃姫 - gnuutera2012or文句うさびょん URL
2024/04/12 (Fri) 23:31:16
REM 十進BASIC 桃太郎
LET OJIISANN$="お殿様"
LET OBAASANN$="お姫様"
LET YAMA$="山"
LET KAWA$="川"
LET SIBAKARI$="鷹狩り"
LET SENTAKU$="お茶会"
LET OOKINA$="大きな"
LET MOMO$="ピーチパイ"
LET DONBURAKO$="えんやーとっと"
LET HOUTYOU$="包丁"
LET OTOKONO$="おんなの"
LET AKANBOU$="赤ん坊"
LET MOMOTAROU$="桃姫"
LET ONI$="ダンサー"
LET GA$="が"
LET SIMA$="島"
LET TAIJI$="勝負"
LET KATANA$="LEDサイネージ"
LET KOGATANA$="蛍光塗料"
LET ISHOU$="衣装"
LET HATA$="旗"
LET NIPPONNICHI$="日本一"
LET KIBIDANNGO$="プロテイン"
LET INU$="ケン"
LET WANWAN$="ヒャッハー!"
LET SARU$="モンタナ"
LET KYAKKKYA$="あらよっと!"
LET KIJI$="太郎"
LET KENKEN$="(♪♪♪♪♪)"
LET FUNE$="舟"
LET UTAGE$="宴"
LET KAMITUKI$="握手し"
LET HIKKAKI$="握手し"
LET TUTUKI$="握手し"
LET WARUIKOTO$="ダンス"
LET TAKARAMONO$="宝物"
PRINT "むかしむかし、あるところに"&OJIISANN$&"と"&OBAASANN$&"がいました。"
PRINT OJIISANN$&"は"&YAMA$&"へ"&SIBAKARI$&"に、"&OBAASANN$&"は"&KAWA$&"へ"&SENTAKU$&"にいきました。"
PRINT OBAASANN$&"がせんたくをしていると、"&KAWA$&"から"&OOKINA$&MOMO$&"が"&DONBURAKO$&DONBURAKO$&"とながれてきました。"
PRINT OBAASANN$&"は"&OJIISANN$&"と"&MOMO$&"をたべようとおもって、"&OOKINA$&MOMO$&"をうちにもちかえりました。"
PRINT "やまからかえってきた"&OJIISANN$&"は、"&OOKINA$&MOMO$&"だとさっそく"&HOUTYOU$&"できろうとしたところ、"
PRINT MOMO$&"のなかから"&OTOKONO$&AKANBOU$&"がげんきよくとびだしてきました。"
PRINT OJIISANN$&"は"&AKANBOU$&"に"&MOMOTAROU$&"となづけました。"
PRINT MOMOTAROU$&"はすくすくとそだっていき、やがて、りっぱにそだつと、"
PRINT OJIISANN$&"と"&OBAASANN$&"に"&ONI$&GA$&SIMA$&"へ"&ONI$&TAIJI$&"にいきたいともうしでました。"
PRINT OJIISANN$&"と"&OBAASANN$&"は、おそろしい"&ONI$&"がすんでいる"&ONI$&GA$&SIMA$&"へ"
PRINT MOMOTAROU$&"をいかせまいとひっしになだめすかしますが、"&MOMOTAROU$&"はがんとしてききません。"
PRINT "しかたなく、"&OJIISANN$&"は"&MOMOTAROU$&"に"&KATANA$&"と"&KOGATANA$&"を、"
PRINT OBAASANN$&"は、"&ISHOU$&"と"&NIPPONNICHI$&"の"&HATA$&"をそろえ、"&MOMOTAROU$&"にさずけました。"
PRINT MOMOTAROU$&"がしゅっぱつするひに、"&OBAASANN$&"はどうちゅうのはらごしらえにと、"
PRINT KIBIDANNGO$&"を"&MOMOTAROU$&"にもたせました。"
PRINT MOMOTAROU$&"は"&OJIISANN$&"、"&OBAASANN$&"、いってまいります。と、げんきよくしゅっぱつしました。"
PRINT MOMOTAROU$&"があるいていると、みちのむかいから"&INU$&"が、"&WANWAN$&"、"&MOMOTAROU$&"さん、"
PRINT "おこしにつけた"&KIBIDANNGO$&"をひとつくれたらけらいになりましょう、"&WANWAN$&"。とたのむので、"
PRINT MOMOTAROU$&"は"&INU$&"に"&KIBIDANNGO$&"をひとつわけてやりました。"
PRINT MOMOTAROU$&"と、"&INU$&"がみちをあるいていくと、みちのむかいから"&SARU$&"が、"&KYAKKKYA$&"、"&MOMOTAROU$&"さん、"
PRINT "おこしにつけた"&KIBIDANNGO$&"をひとつくれたらけらいになりましょう、"&KYAKKKYA$&"。とたのむので、"
PRINT MOMOTAROU$&"は"&SARU$&"にも"&KIBIDANNGO$&"をひとつわけてやりました。"
PRINT MOMOTAROU$&"と、"&INU$&"と"&SARU$&"がみちをあるいていくと、みちのむかいから"&KIJI$&"が、"&KENKEN$&"、"&MOMOTAROU$&"さん、"
PRINT "おこしにつけた"&KIBIDANNGO$&"をひとつくれたらけらいになりましょう、"&KENKEN$&"。とたのむので、"
PRINT MOMOTAROU$&"は"&KIJI$&"にも"&KIBIDANNGO$&"をひとつわけてやりました。"
PRINT "こうして、"&INU$&"、"&SARU$&"、"&KIJI$&"をおともにしたがえた"&MOMOTAROU$&"は、"&FUNE$&"にのって"
PRINT ONI$&GA$&SIMA$&"につきました。"
PRINT ONI$&GA$&SIMA$&"ではおそろしい"&ONI$&"たちが"&UTAGE$&"のまっさいちゅう。"
PRINT ONI$&"ども、この"&MOMOTAROU$&"がせいばいしてくれる。"
PRINT MOMOTAROU$&"は"&KATANA$&"と"&KOGATANA$&"で"&ONI$&"たちに"&"せまります。"
PRINT INU$&"、"&SARU$&"、"&KIJI$&"もそこへおそいかかります。"
PRINT INU$&"は"&ONI$&"に"&KAMITUKI$&"ます。"
PRINT SARU$&"は"&ONI$&"に"&HIKKAKI$&"ます。"
PRINT KIJI$&"はそらから"&ONI$&"を"&TUTUKI$&"ます。"
PRINT "さすがの"&ONI$&"どももこうさんしました。"
PRINT MOMOTAROU$&"さん。たすけてください。"
PRINT ONI$&GA$&SIMA$&"の"&TAKARAMONO$&"をぜんぶさしあげます。"
PRINT "もうわるいことはいたしません。"
PRINT "ひっしで"&ONI$&"たちがたのむので、"&MOMOTAROU$&"は、"
PRINT "いいだろう。もう"&WARUIKOTO$&"はするなよと、"&ONI$&"たちをゆるしてやりました。"
PRINT "こうして、"&TAKARAMONO$&"を"&FUNE$&"につんで、"&ONI$&"たちにみおくられながら"
PRINT MOMOTAROU$&"、"&INU$&"、"&SARU$&"、"&KIJI$&"、のいっこうは、"&ONI$&"が"&SIMA$&"をあとにしました。"
PRINT MOMOTAROU$&"、"&INU$&"、"&SARU$&"、"&KIJI$&"が"&OJIISANN$&"と、"&OBAASANN$&"のいえにつくと、"
PRINT OJIISANN$&"と、"&OBAASANN$&"はたいそうよろこびました。"
PRINT MOMOTAROU$&"は、"&ONI$&GA$&SIMA$&"で"&ONI$&"たちをせいばいしたこと、"
PRINT ONI$&"たちにもらった"&TAKARAMONO$&"のことをはなしました。"
PRINT ONI$&"たちにもらった"&TAKARAMONO$&"で、"&MOMOTAROU$&"、"&OJIISANN$&"、"&OBAASANN$&"、"
PRINT INU$&"、"&SARU$&"、"&KIJI$&"はいつまでもたのしくくらしたということです。"
PRINT "めでたしめでたし。"
むかしむかし、あるところにお殿様とお姫様がいました。
お殿様は山へ鷹狩りに、お姫様は川へお茶会にいきました。
お姫様がせんたくをしていると、川から大きなピーチパイがえんやーとっとえんやーとっととながれてきました。
お姫様はお殿様とピーチパイをたべようとおもって、大きなピーチパイをうちにもちかえりました。
やまからかえってきたお殿様は、大きなピーチパイだとさっそく包丁できろうとしたところ、
ピーチパイのなかからおんなの赤ん坊がげんきよくとびだしてきました。
お殿様は赤ん坊に桃姫となづけました。
桃姫はすくすくとそだっていき、やがて、りっぱにそだつと、
お殿様とお姫様にダンサーが島へダンサー勝負にいきたいともうしでました。
お殿様とお姫様は、おそろしいダンサーがすんでいるダンサーが島へ
桃姫をいかせまいとひっしになだめすかしますが、桃姫はがんとしてききません。
しかたなく、お殿様は桃姫にLEDサイネージと蛍光塗料を、
お姫様は、衣装と日本一の旗をそろえ、桃姫にさずけました。
桃姫がしゅっぱつするひに、お姫様はどうちゅうのはらごしらえにと、
プロテインを桃姫にもたせました。
桃姫はお殿様、お姫様、いってまいります。と、げんきよくしゅっぱつしました。
桃姫があるいていると、みちのむかいからケンが、ヒャッハー!、桃姫さん、
おこしにつけたプロテインをひとつくれたらけらいになりましょう、ヒャッハー!。とたのむので、
桃姫はケンにプロテインをひとつわけてやりました。
桃姫と、ケンがみちをあるいていくと、みちのむかいからモンタナが、あらよっと!、桃姫さん、
おこしにつけたプロテインをひとつくれたらけらいになりましょう、あらよっと!。とたのむので、
桃姫はモンタナにもプロテインをひとつわけてやりました。
桃姫と、ケンとモンタナがみちをあるいていくと、みちのむかいから太郎が、(♪♪♪♪♪)、桃姫さん、
おこしにつけたプロテインをひとつくれたらけらいになりましょう、(♪♪♪♪♪)。とたのむので、
桃姫は太郎にもプロテインをひとつわけてやりました。
こうして、ケン、モンタナ、太郎をおともにしたがえた桃姫は、舟にのって
ダンサーが島につきました。
ダンサーが島ではおそろしいダンサーたちが宴のまっさいちゅう。
ダンサーども、この桃姫がせいばいしてくれる。
桃姫はLEDサイネージと蛍光塗料でダンサーたちにせまります。
ケン、モンタナ、太郎もそこへおそいかかります。
ケンはダンサーに握手します。
モンタナはダンサーに握手します。
太郎はそらからダンサーを握手します。
さすがのダンサーどももこうさんしました。
桃姫さん。たすけてください。
ダンサーが島の宝物をぜんぶさしあげます。
もうわるいことはいたしません。
ひっしでダンサーたちがたのむので、桃姫は、
いいだろう。もうダンスはするなよと、ダンサーたちをゆるしてやりました。
こうして、宝物を舟につんで、ダンサーたちにみおくられながら
桃姫、ケン、モンタナ、太郎、のいっこうは、ダンサーが島をあとにしました。
桃姫、ケン、モンタナ、太郎がお殿様と、お姫様のいえにつくと、
お殿様と、お姫様はたいそうよろこびました。
桃姫は、ダンサーが島でダンサーたちをせいばいしたこと、
ダンサーたちにもらった宝物のことをはなしました。
ダンサーたちにもらった宝物で、桃姫、お殿様、お姫様、
ケン、モンタナ、太郎はいつまでもたのしくくらしたということです。
めでたしめでたし。
END
誘導員管理表 - gnuutera2012or文句うさびょん URL
2024/04/12 (Fri) 00:40:51
誘導員管理表です。
コピーアンドペーストする前に"ctrl" + "-" で文字を小さくするとうまくいくかもしれません。33%縮小でプログラムとして使えるようになりました。
▼と▲の間がプログラムで、RUNが未入力時の実行結果です。
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
http://yutorinonatuyasumi.blog.fc2.com/blog-entry-297.html
マンデルバルブ - しばっち
2024/03/31 (Sun) 08:56:22
マンデルバルブ
https://en.wikipedia.org/wiki/Mandelbulb
このプログラムは下記からの移植版です。
https://glslsandbox.com/e#55840.0
もし、ご興味ある方は専用のソフトが公開されています。
https://www.mandelbulb.com/
DIM ST(3),RO(3),TA(3),UP(3),X(3),Y(3),Z(3),T1(3),T2(3),T3(3)
DIM TT(3),RD(3),POS(3),BG(3),C(3),NOR(3)
ASK BITMAP SIZE XSIZE,YSIZE
SET COLOR MODE "NATIVE"
SET POINT STYLE 1
SET WINDOW -XSIZE/MIN(XSIZE,YSIZE),XSIZE/MIN(XSIZE,YSIZE),-YSIZE/MIN(XSIZE,YSIZE),YSIZE/MIN(XSIZE,YSIZE)
FOR YY=0 TO YSIZE-1
FOR XX=0 TO XSIZE-1
LET ST(1)=(XX*2-XSIZE)/MIN(XSIZE,YSIZE)
LET ST(2)=(YY*2-YSIZE)/MIN(XSIZE,YSIZE)
CALL VEC3(RO,0.0, 0.0, 2.5)
CALL VEC3(TA,0,0,0)
MAT TT=TA-RO
CALL NORMALIZE(TT,Z)
CALL VEC3(UP,0.0, 1.0, 0.0)
MAT TT=CROSS(Z,UP)
CALL NORMALIZE(TT,X)
MAT TT=CROSS(X,Z)
CALL NORMALIZE(TT,Y)
MAT T1=ST(1)*X
MAT T2=ST(2)*Y
MAT T3=1.5*Z
MAT TT=T1+T2
MAT TT=TT+T3
CALL NORMALIZE(TT,RD)
CALL RAYMARCH(RO,RD,T,RET)
IF RET=1 THEN
MAT TT=T*RD
MAT POS = RO + TT
CALL CALCNORMAL(POS,NOR)
CALL SHADESURFACE(POS, NOR,C)
ELSE
LET BG(1)=(2*XX-XSIZE)/XSIZE
LET BG(2)=(2*YY-YSIZE)/YSIZE
CALL BACKGROUND(BG,C)
END IF
CALL SETCOLOR(ABS(C(1))^(1/2.2),ABS(C(2))^(1/2.2),ABS(C(3))^(1/2.2))
PLOT POINTS:WORLDX(XX),WORLDY(YY)
NEXT XX
NEXT YY
END
EXTERNAL FUNCTION DEMANDELBULB(P(), POWER)
DIM S(3),Z(3)
MAT Z = P
LET ITERATIONS=8
LET DR = 1.0
FOR I = 0 TO ITERATIONS-1
LET R = LENGTH(Z)
IF R > 10 THEN EXIT FOR
IF R=0 THEN
LET THETA=0
ELSE
LET THETA = ACOS(Z(2) / R)
END IF
IF Z(1)=0 AND Z(3)=0 THEN
LET PHI=0
ELSE
LET PHI = ANGLE(Z(1),Z(3))
END IF
LET DR = R^(POWER - 1) * POWER * DR + 1
LET ZR = R^POWER
LET THETA = THETA * POWER
LET PHI = PHI * POWER
CALL VEC3(S,SIN(THETA) * COS(PHI), COS(THETA), SIN(THETA) * SIN(PHI))
MAT Z = ZR * S
MAT Z = Z+P
NEXT I
LET DEMANDELBULB=0.5 * LOG(R) * R / DR
END FUNCTION
EXTERNAL FUNCTION DE(P())
LET DE=DEMANDELBULB(P, 8)
END FUNCTION
EXTERNAL FUNCTION AMBIENTOCCLUSION(POS(), NOR())
DIM T(3),P(3)
LET OCCLUSION_ITERATIONS=5
LET AMP = 0.5
LET STEP = 0.02
FOR I = 1 TO OCCLUSION_ITERATIONS-1
MAT T=(STEP * I) * NOR
MAT P = POS + T
LET D = DE(P)
LET AO =AO+ AMP * ((STEP * I - D) / (STEP * I))
LET AMP =AMP* 0.5
NEXT I
LET AMBIENTOCCLUSION=1.0 - AO
END FUNCTION
EXTERNAL SUB SHADESURFACE(POS(), NOR(),ANS())
DIM LIGHT_DIR(3),DIFFUSE_COLOR(3),AMBIENT_COLOR(3)
DIM DIF(3),AMB(3)
CALL VEC3(LIGHT_DIR,.5,.8,1)
CALL NORMALIZE(LIGHT_DIR,LIGHT_DIR)
CALL VEC3(DIFFUSE_COLOR,.8,.8,.8)
CALL VEC3(AMBIENT_COLOR,.2,.2,.2)
LET DOTNL = MAX(0.0, DOT(NOR, LIGHT_DIR))
MAT DIF = DOTNL*DIFFUSE_COLOR
LET AO = AMBIENTOCCLUSION(POS, NOR)
MAT AMB = AO*AMBIENT_COLOR
MAT ANS=DIF + AMB
END SUB
EXTERNAL SUB RAYMARCH(RO(), RD(), T,RET)
DIM P(3),TT(3)
MAT P = RO
LET T = 0.0
FOR I = 0 TO 31
LET D = DE(P)
MAT TT=D*RD
MAT P = P+TT
IF LENGTH(P)>10 THEN EXIT FOR
LET T =T+ D
IF (D < 0.002) THEN
LET RET=1 ! true
EXIT SUB
END IF
NEXT I
LET RET=0 ! false
END SUB
EXTERNAL SUB BACKGROUND(ST(),ANS())
DIM S(3),T(3)
CALL VEC3(S,.5,.5,.5)
CALL VEC3(T,.1,.1,.1)
FOR I=1 TO 3
LET ANS(I)=MIX(S(I), T(I), LENGTH(ST) * 0.8)
NEXT I
END SUB
EXTERNAL SUB CALCNORMAL(P(),N())
DIM X1(3),X2(3),Y1(3),Y2(3),Z1(3),Z2(3),PX1(3),PX2(3),PY1(3),PY2(3),PZ1(3),PZ2(3)
LET D=.0001
CALL VEC3(X1,D,0,0)
CALL VEC3(X2,-D,0,0)
MAT PX1=P+X1
MAT PX2=P+X2
CALL VEC3(Y1,0,D,0)
CALL VEC3(Y2,0,-D,0)
MAT PY1=P+Y1
MAT PY2=P+Y2
CALL VEC3(Z1,0,0,D)
CALL VEC3(Z2,0,0,-D)
MAT PZ1=P+Z1
MAT PZ2=P+Z2
CALL VEC3(N,DE(PX1)-DE(PX2),DE(PY1)-DE(PY2),DE(PZ1)-DE(PZ2))
CALL NORMALIZE(N,N)
END SUB
EXTERNAL SUB NORMALIZE(RAY(),ANS())
DIM T(3)
LET S=LENGTH(RAY)
IF S<>0 THEN
MAT T=(1/S)*RAY
ELSE
MAT T=ZER
END IF
MAT ANS=T
END SUB
EXTERNAL SUB SETCOLOR(R,G,B)
SET COLOR COLORINDEX(CLAMP(R,0,1),CLAMP(G,0,1),CLAMP(B,0,1))
END SUB
EXTERNAL SUB VEC3(V(),X,Y,Z)
LET V(1)=X
LET V(2)=Y
LET V(3)=Z
END SUB
EXTERNAL FUNCTION LENGTH(A())
LET LENGTH=SQR(A(1)^2+A(2)^2+A(3)^2)
END FUNCTION
EXTERNAL FUNCTION CLAMP(X,A,B)
LET CLAMP=MIN(B,MAX(X,A))
END FUNCTION
EXTERNAL FUNCTION MIX(X,Y,A)
LET MIX=X*(1-A)+Y*A
END FUNCTION
テキストファイルの文字コード - gnuutera2012or文句うさぴょん URL
2024/03/08 (Fri) 09:08:57
編集済みのテキストファイルを十進basicに貼り付けたら文字化けしてできなかったものの、
色々試して復旧できたので御報告いたします。
現象が発生したら一旦すべてコピーして、名前をつけて保存します。
この際に文字コードをANJIにして保存してください。
この操作後でしたら貼り付けても文字化けは発生しないはずです。
既出事項でしたら申し訳ございません。
Re: テキストファイルの文字コード - しばっち
2024/03/10 (Sun) 09:05:37
下記プログラムでUTF-8からSHIFT-JISに変換できます。
SET文を入れ替えるとSHIFT-JISからUTF-8にもできます。
改造(FILES文及びFILE LIST文)すれば複数まとめて変換もできるようになります。
FILE GETOPENNAME F$, "テキストファイル|*.txt;*.bas"
IF F$="" THEN STOP
FOR I=LEN(F$) TO 1 STEP -1
IF F$(I:I)="\" THEN EXIT FOR
NEXT I
OPEN #1:NAME F$
OPEN #2:NAME F$(1:I)&"変換済み."&F$(LEN(F$)-2:LEN(F$))
SET #1:CODING "UTF-8"
SET #2:CODING "SYSTEM"
DO
LINE INPUT #1,IF MISSING THEN EXIT DO:A$
PRINT #2:A$
LOOP
CLOSE #1
CLOSE #2
END
月齢カレンダーの修正 - gnuutera2012or文句うさぴょん URL
2024/03/08 (Fri) 08:34:23
!' カレンダー
!'
!' 投稿者:しばっち
!' 投稿日:2014年 9月 2日(火)19時16分5秒 通報 返信・引用
!'
!' ----------------------------------------------------------------------------------------------------
!' 加筆修正者:gnuutera2012
!' ※新元号が令和となり、あちこち加筆修正させていただきました。
!' (例)
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
!' 加筆修正加筆修正加筆修正加筆修正加筆修正加筆修正
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
!' ----------------------------------------------------------------------------------------------------
DECLARE EXTERNAL FUNCTION SHUKU28$
DECLARE EXTERNAL FUNCTION CALC_ETO60$
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
DECLARE EXTERNAL FUNCTION TYOKU12$
DECLARE EXTERNAL FUNCTION CALC_ETO61$
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
PUBLIC STRING SEKKI24$(0 TO 23, 0 TO 1),QROKUYOU$,QJUKKAN$,Z$
PUBLIC NUMERIC QYEAR,QURUU,QMONTH,QDAY,QMAGE,QMAGENOON,QILLUMI,QMPHASE,RM_SUN0
LET A4=297/210
!' LET B5=257/182
!' LET B4=364/257
LET XSIZE=800
LET YSIZE=INT(XSIZE*A4)
LET XS=XSIZE*75/800
LET YS=YSIZE*250/800
CALL GINIT(XSIZE,YSIZE)
LET HEIGHT=XSIZE*50/800
SET TEXT HEIGHT HEIGHT
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
!' センター数学(BASIC)による「ゲームプログラミングの宝箱」をダウンロードして、実例\ユーティリティー\時間・日付\カレンダー.BASを開く。
!' https://hp.vector.co.jp/authors/VA008683/QA_Primary.htmも参照。
FUNCTION IsLeapYear(y) ! うるう年の判定
LET IsLeapYear=0
IF (MOD(y,4)=0 AND MOD(y,100)<>0) OR MOD(y,400)=0 THEN LET IsLeapYear=1 ! うるう年
END FUNCTION
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
DIM DD(12),MON$(12)
MAT READ DD
DATA 31,28,31,30,31,30,31,31,30,31,30,31
MAT READ MON$
DATA "睦月","如月","弥生","卯月","皐月","水無月","文月","葉月","長月","神無月","霜月","師走"
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
!' LET YEAR = INT(VAL(DATE$)/10000)
!' LET MONTH = MOD(INT(VAL(DATE$)/100),100)
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
INPUT PROMPT "西暦=":YEAR$
IF YEAR$<>"" THEN LET YEAR=VAL(YEAR$)
INPUT PROMPT "月=":MONTH$
IF MONTH$<>"" THEN LET MONTH=VAL(MONTH$)
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
IF IsLeapYear(YEAR)<>0 THEN LET DD(2)=29 !うるう年なら
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
LET TM = YMDT2JD(YEAR, MONTH, 1, 0, 0, 0)
LET R=MOD(TM+2,7)
SET LINE COLOR "BLACK"
LET XX=R*XSIZE/8
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
IF ((YEAR= 2019 AND MONTH>= 5) AND (YEAR= 2019 AND MONTH=<12)) OR (YEAR>=2020 AND MONTH>= 1) THEN LET M$=" 令和"&STR$(YEAR-2018)&"年" !' 令和元年は2019年5月1日から。
IF ((YEAR>=1989 AND MONTH>= 1) AND (YEAR=<2018 AND MONTH=<12)) OR ((YEAR= 2019 AND MONTH>= 1) AND (YEAR= 2019 AND MONTH=< 4)) THEN LET M$=" 平成"&STR$(YEAR-1988)&"年" !' IF YEAR=<2018 AND YEAR>=1989 THEN LET GENGOUNEN$=STR$(YEAR-1988)
IF ((YEAR>=1926 AND MONTH>= 1) AND (YEAR=<1988 AND MONTH=<12)) THEN LET M$=" 昭和"&STR$(YEAR-1925)&"年" !' IF YEAR=<1988 AND YEAR>=1926 THEN LET GENGOUNEN$=STR$(YEAR-1925)
IF ((YEAR= 1912 AND MONTH>= 8) AND (YEAR= 1912 AND MONTH=<12)) OR ((YEAR>=1913 AND MONTH>= 1) AND (YEAR=<1925 AND MONTH=<12)) THEN LET M$=" 大正"&STR$(YEAR-1911)&"年" !' IF YEAR=<1925 AND YEAR>=1912 THEN LET GENGOUNEN$=STR$(YEAR-1911)
IF ((YEAR= 1868 AND MONTH>= 9) AND (YEAR= 1868 AND MONTH=<12)) OR ((YEAR>=1869 AND MONTH>= 1) AND (YEAR=<1911 AND MONTH=<12)) OR ((YEAR= 1912 AND MONTH>= 1) AND (YEAR= 1912 AND MONTH=< 7)) THEN LET M$=" 明治"&STR$(YEAR-1867)&"年" !' IF YEAR=<1911 AND YEAR>=1868 THEN LET GENGOUNEN$=STR$(YEAR-1867)
!' IF YEAR<1989 AND YEAR>=1926 THEN LET M$=" 昭和"&STR$(YEAR-1925)&"年"
!' IF YEAR<1926 AND YEAR>=1912 THEN LET M$=" 大正"&STR$(YEAR-1911)&"年"
!' IF YEAR<1912 AND YEAR>=1868 THEN LET M$=" 明治"&STR$(YEAR-1867)&"年"
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
IF ((YEAR= 2019 AND MONTH>= 5) AND (YEAR= 2019 AND MONTH=<12)) OR (YEAR>=2020 AND MONTH>= 1) THEN LET ERA$="令和"&RIGHT$(" "&STR$(YEAR-2018),2)&"年" ! 令和元年は2019年5月1日から。
IF ((YEAR>=1989 AND MONTH>= 1) AND (YEAR=<2018 AND MONTH=<12)) OR ((YEAR= 2019 AND MONTH>= 1) AND (YEAR= 2019 AND MONTH=< 4)) THEN LET ERA$="平成"&RIGHT$(" "&STR$(YEAR-1988),2)&"年"
IF ((YEAR>=1926 AND MONTH>= 1) AND (YEAR=<1988 AND MONTH=<12)) THEN LET ERA$="昭和"&RIGHT$(" "&STR$(YEAR-1925),2)&"年"
IF ((YEAR= 1912 AND MONTH>= 8) AND (YEAR= 1912 AND MONTH=<12)) OR ((YEAR>=1913 AND MONTH>= 1) AND (YEAR=<1925 AND MONTH=<12)) THEN LET ERA$="大正"&RIGHT$(" "&STR$(YEAR-1911),2)&"年"
IF ((YEAR= 1868 AND MONTH>= 9) AND (YEAR= 1868 AND MONTH=<12)) OR ((YEAR>=1869 AND MONTH>= 1) AND (YEAR=<1911 AND MONTH=<12)) OR ((YEAR= 1912 AND MONTH>= 1) AND (YEAR= 1912 AND MONTH=< 7)) THEN LET ERA$="明治"&RIGHT$(" "&STR$(YEAR-1867),2)&"年"
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
CALL SYMBOL(XSIZE/2-HEIGHT*3,YSIZE/8,"BLACK",STR$(YEAR)&"年"&" "&STR$(MONTH)&"月")
SET TEXT HEIGHT HEIGHT/2
CALL SYMBOL(XSIZE/2+HEIGHT*4,YSIZE/9,"BLACK",M$)
CALL SYMBOL(XSIZE/2+HEIGHT*5,YSIZE/9+HEIGHT*2/3,"BLACK",CALC_ETO60$(YEAR))
CALL SYMBOL(XSIZE/2+HEIGHT*5,YSIZE/9+HEIGHT*4/3,"BLACK",MON$(MONTH))
SET TEXT HEIGHT HEIGHT
FOR I=0 TO 6
READ A$,COL$
DATA "日","RED","月","BLACK","火","BLACK","水","BLACK","木","BLACK","金","BLACK","土","BLUE"
CALL SYMBOL(XS+I*XSIZE/8,YSIZE/4,COL$,A$)
NEXT I
CALL CALC_SEKKI24(YEAR)
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
! メモ帳に用いる場合に使う。
PRINT USING ">######## >######## ":RIGHT$(" "&YEAR$,4)&"年",RIGHT$(" "&MONTH$,2)&"月"
PRINT USING ">######## >######## ":ERA$,MON$(MONTH)
PRINT USING ">######## ":CALC_ETO60$(YEAR)
PRINT USING " ######## #### ################ ########## ######## ######## ###### #### #### #### ######## ###### ######## ##########":"新暦","曜日","祝祭日","旧暦","零時月齢","正午月齢","輝面比","月相","六曜","干支","九星","十二直","二十八宿","二十四節気"
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
FOR I=1 TO DD(MONTH)
LET FL=0
SET TEXT HEIGHT HEIGHT
LET COL$=DAYCOLOR$(YEAR,MONTH,I,R)
CALL SYMBOL(XS+XX,YS+YY,COL$,USING$("##",I))
CALL CALC_KYUREKI(YEAR,MONTH,I)
IF QURUU<>0 THEN LET N$="閏" ELSE LET N$=""
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
IF QMONTH=1 AND QDAY=1 THEN LET Z$="旧正月"
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
LET TM = YMDT2JD(YEAR, MONTH, I, 0, 0, 0)
LET A$=CALC_JUKKAN$(TM)
LET B$=QSEI$(TM)
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
! メモ帳に用いる場合に使う。
LET C$=MEMO_JUKKAN$(TM)
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
! メモ帳に用いる場合に使う。
IF MONTH=1 OR MONTH=2 THEN LET ye=YEAR-1
IF MONTH=1 THEN LET mo=13
IF MONTH=2 THEN LET mo=14
IF MONTH<>1 AND MONTH<>2 THEN LET ye=YEAR
IF MONTH<>1 AND MONTH<>2 THEN LET mo=MONTH
LET c=INT(ye/100)
LET n=ye-INT(ye/100)*100
LET NIJYUUHASSHUKU=MOD(INT(12.25*c)+INT(1.25*n)+INT(2.6*(mo+1))+16+I,28)
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
DIM SEKKIOF24$(31)
FOR K=0 TO 23
IF VAL(SEKKI24$(K, 0)(6:7))=MONTH AND VAL(SEKKI24$(K, 0)(9:10))=I THEN
IF Z$<>"" THEN
LET SEKKIOF24$(I)=SEKKI24$(K, 1)
LET FL=1
ELSE
LET SEKKIOF24$(I)=SEKKI24$(K, 1)
LET FL=2
END IF
EXIT FOR
END IF
NEXT K
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
LET JDSHOUKANN=YMDT2JD(YEAR, VAL(SEKKI24$(0, 0)(6:6))*10+VAL(SEKKI24$(0, 0)(7:7)), VAL(SEKKI24$(0, 0)(9:9))*10+VAL(SEKKI24$(0, 0)(10:10)), 0, 0, 0)
FOR JUSHI=1 TO 12 !' Jではなく、JUSHIとする。
LET JDSHOUKANNUSHIKOUHO=JDSHOUKANN+JUSHI !' Jではなく、JUSHIとする。
LET DATEOFSHOUKANNUSHIKOUHO$=JD2YMDT$(JDSHOUKANNUSHIKOUHO)
LET SHOUKANNUSHIKOUHOMONTH=VAL(DATEOFSHOUKANNUSHIKOUHO$(6:6))*10+VAL(DATEOFSHOUKANNUSHIKOUHO$(7:7))
LET SHOUKANNUSHIKOUHODAY=VAL(DATEOFSHOUKANNUSHIKOUHO$(9:9))*10+VAL(DATEOFSHOUKANNUSHIKOUHO$(10:10))
LET TM=YMDT2JD(YEAR,SHOUKANNUSHIKOUHOMONTH,SHOUKANNUSHIKOUHODAY, 0, 0, 0)
IF SHOUKANNUSHIKOUHOMONTH=1 OR SHOUKANNUSHIKOUHOMONTH=2 THEN LET ye=YEAR-1
IF SHOUKANNUSHIKOUHOMONTH=1 THEN LET mo=13
IF SHOUKANNUSHIKOUHOMONTH=2 THEN LET mo=14
IF SHOUKANNUSHIKOUHOMONTH<>1 AND SHOUKANNUSHIKOUHOMONTH<>2 THEN LET ye=YEAR
IF SHOUKANNUSHIKOUHOMONTH<>1 AND SHOUKANNUSHIKOUHOMONTH<>2 THEN LET mo=SHOUKANNUSHIKOUHOMONTH
LET c=INT(ye/100)
LET n=ye-INT(ye/100)*100
LET JYUUNISHIJOUYOKEI=MOD(INT(44.25*c)+INT(5.25*n)+INT(30.6*(mo+1))+6+SHOUKANNUSHIKOUHODAY,12)
LET ETOMOJIWATASHI$=CALC_ETO61$(JYUUNISHIJOUYOKEI) !' IF SHOUKANNUSHIKOUHODAY>SD THENは不要かも?結局削除した。
IF ETOMOJIWATASHI$(2:2)="丑" THEN LET SHOUKANNUSHIMONTH=SHOUKANNUSHIKOUHOMONTH
IF ETOMOJIWATASHI$(2:2)="丑" THEN LET SHOUKANNUSHIDAY=SHOUKANNUSHIKOUHODAY
IF ETOMOJIWATASHI$(2:2)="丑" THEN EXIT FOR
NEXT JUSHI !' Jではなく、JUSHIとする。
LET JDRISSHUNN=YMDT2JD(YEAR, VAL(SEKKI24$(2, 0)(6:6))*10+VAL(SEKKI24$(2, 0)(7:7)), VAL(SEKKI24$(2, 0)(9:9))*10+VAL(SEKKI24$(2, 0)(10:10)), 0, 0, 0)
FOR JTORA=1 TO 12 !' Jではなく、JTORAとする。
LET JDRISSHUNNTORAKOUHO=JDRISSHUNN+JTORA !' Jではなく、JTORAとする。
LET DATEOFRISSHUNNTORAKOUHO$=JD2YMDT$(JDRISSHUNNTORAKOUHO)
LET RISSHUNNTORAKOUHOMONTH=VAL(DATEOFRISSHUNNTORAKOUHO$(6:6))*10+VAL(DATEOFRISSHUNNTORAKOUHO$(7:7))
LET RISSHUNNTORAKOUHODAY=VAL(DATEOFRISSHUNNTORAKOUHO$(9:9))*10+VAL(DATEOFRISSHUNNTORAKOUHO$(10:10))
LET TM=YMDT2JD(YEAR,RISSHUNNTORAKOUHOMONTH,RISSHUNNTORAKOUHODAY, 0, 0, 0)
IF RISSHUNNTORAKOUHOMONTH=1 OR RISSHUNNTORAKOUHOMONTH=2 THEN LET ye=YEAR-1
IF RISSHUNNTORAKOUHOMONTH=1 THEN LET mo=13
IF RISSHUNNTORAKOUHOMONTH=2 THEN LET mo=14
IF RISSHUNNTORAKOUHOMONTH<>1 AND RISSHUNNTORAKOUHOMONTH<>2 THEN LET ye=YEAR
IF RISSHUNNTORAKOUHOMONTH<>1 AND RISSHUNNTORAKOUHOMONTH<>2 THEN LET mo=RISSHUNNTORAKOUHOMONTH
LET c=INT(ye/100)
LET n=ye-INT(ye/100)*100
LET JYUUNISHIJOUYOKEI=MOD(INT(44.25*c)+INT(5.25*n)+INT(30.6*(mo+1))+6+RISSHUNNTORAKOUHODAY,12)
LET ETOMOJIWATASHI$=CALC_ETO61$(JYUUNISHIJOUYOKEI) !' IF RISSHUNNTORAKOUHODAY>SD THENは不要かも?結局削除した。
IF ETOMOJIWATASHI$(2:2)="寅" THEN LET RISSHUNNTORAMONTH=RISSHUNNTORAKOUHOMONTH
IF ETOMOJIWATASHI$(2:2)="寅" THEN LET RISSHUNNTORADAY=RISSHUNNTORAKOUHODAY
IF ETOMOJIWATASHI$(2:2)="寅" THEN EXIT FOR
NEXT JTORA !' Jではなく、JTORAとする。
LET JDKEICHITU=YMDT2JD(YEAR, VAL(SEKKI24$(4, 0)(6:6))*10+VAL(SEKKI24$(4, 0)(7:7)), VAL(SEKKI24$(4, 0)(9:9))*10+VAL(SEKKI24$(4, 0)(10:10)), 0, 0, 0)
FOR JUU=1 TO 12 !' Jではなく、JUUとする。
LET JDKEICHITUUUKOUHO=JDKEICHITU+JUU !' Jではなく、JUUとする。
LET DATEOFKEICHITUUUKOUHO$=JD2YMDT$(JDKEICHITUUUKOUHO)
LET KEICHITUUUKOUHOMONTH=VAL(DATEOFKEICHITUUUKOUHO$(6:6))*10+VAL(DATEOFKEICHITUUUKOUHO$(7:7))
LET KEICHITUUUKOUHODAY=VAL(DATEOFKEICHITUUUKOUHO$(9:9))*10+VAL(DATEOFKEICHITUUUKOUHO$(10:10))
LET TM=YMDT2JD(YEAR,KEICHITUUUKOUHOMONTH,KEICHITUUUKOUHODAY, 0, 0, 0)
IF KEICHITUUUKOUHOMONTH=1 OR KEICHITUUUKOUHOMONTH=2 THEN LET ye=YEAR-1
IF KEICHITUUUKOUHOMONTH=1 THEN LET mo=13
IF KEICHITUUUKOUHOMONTH=2 THEN LET mo=14
IF KEICHITUUUKOUHOMONTH<>1 AND KEICHITUUUKOUHOMONTH<>2 THEN LET ye=YEAR
IF KEICHITUUUKOUHOMONTH<>1 AND KEICHITUUUKOUHOMONTH<>2 THEN LET mo=KEICHITUUUKOUHOMONTH
LET c=INT(ye/100)
LET n=ye-INT(ye/100)*100
LET JYUUNISHIJOUYOKEI=MOD(INT(44.25*c)+INT(5.25*n)+INT(30.6*(mo+1))+6+KEICHITUUUKOUHODAY,12)
LET ETOMOJIWATASHI$=CALC_ETO61$(JYUUNISHIJOUYOKEI) !' IF KEICHITUUUKOUHODAY>SD THENは不要かも?結局削除した。
IF ETOMOJIWATASHI$(2:2)="卯" THEN LET KEICHITUUUMONTH=KEICHITUUUKOUHOMONTH
IF ETOMOJIWATASHI$(2:2)="卯" THEN LET KEICHITUUUDAY=KEICHITUUUKOUHODAY
IF ETOMOJIWATASHI$(2:2)="卯" THEN EXIT FOR
NEXT JUU !' Jではなく、JUUとする。
LET JDSEIMEI=YMDT2JD(YEAR, VAL(SEKKI24$(6, 0)(6:6))*10+VAL(SEKKI24$(6, 0)(7:7)), VAL(SEKKI24$(6, 0)(9:9))*10+VAL(SEKKI24$(6, 0)(10:10)), 0, 0, 0)
FOR JTATSU=1 TO 12 !' Jではなく、JTATSUとする。
LET JDSEIMEITATSUKOUHO=JDSEIMEI+JTATSU !' Jではなく、JTATSUとする。
LET DATEOFSEIMEITATSUKOUHO$=JD2YMDT$(JDSEIMEITATSUKOUHO)
LET SEIMEITATSUKOUHOMONTH=VAL(DATEOFSEIMEITATSUKOUHO$(6:6))*10+VAL(DATEOFSEIMEITATSUKOUHO$(7:7))
LET SEIMEITATSUKOUHODAY=VAL(DATEOFSEIMEITATSUKOUHO$(9:9))*10+VAL(DATEOFSEIMEITATSUKOUHO$(10:10))
LET TM=YMDT2JD(YEAR,SEIMEITATSUKOUHOMONTH,SEIMEITATSUKOUHODAY, 0, 0, 0)
IF SEIMEITATSUKOUHOMONTH=1 OR SEIMEITATSUKOUHOMONTH=2 THEN LET ye=YEAR-1
IF SEIMEITATSUKOUHOMONTH=1 THEN LET mo=13
IF SEIMEITATSUKOUHOMONTH=2 THEN LET mo=14
IF SEIMEITATSUKOUHOMONTH<>1 AND SEIMEITATSUKOUHOMONTH<>2 THEN LET ye=YEAR
IF SEIMEITATSUKOUHOMONTH<>1 AND SEIMEITATSUKOUHOMONTH<>2 THEN LET mo=SEIMEITATSUKOUHOMONTH
LET c=INT(ye/100)
LET n=ye-INT(ye/100)*100
LET JYUUNISHIJOUYOKEI=MOD(INT(44.25*c)+INT(5.25*n)+INT(30.6*(mo+1))+6+SEIMEITATSUKOUHODAY,12)
LET ETOMOJIWATASHI$=CALC_ETO61$(JYUUNISHIJOUYOKEI) !' IF SEIMEITATSUKOUHODAY>SD THENは不要かも?結局削除した。
IF ETOMOJIWATASHI$(2:2)="辰" THEN LET SEIMEITATSUMONTH=SEIMEITATSUKOUHOMONTH
IF ETOMOJIWATASHI$(2:2)="辰" THEN LET SEIMEITATSUDAY=SEIMEITATSUKOUHODAY
IF ETOMOJIWATASHI$(2:2)="辰" THEN EXIT FOR
NEXT JTATSU !' Jではなく、JTATSUとする。
LET JDRIKKA=YMDT2JD(YEAR, VAL(SEKKI24$(8, 0)(6:6))*10+VAL(SEKKI24$(8, 0)(7:7)), VAL(SEKKI24$(8, 0)(9:9))*10+VAL(SEKKI24$(8, 0)(10:10)), 0, 0, 0)
FOR JMI=1 TO 12 !' Jではなく、JMIとする。
LET JDRIKKAMIKOUHO=JDRIKKA+JMI !' Jではなく、JMIとする。
LET DATEOFRIKKAMIKOUHO$=JD2YMDT$(JDRIKKAMIKOUHO)
LET RIKKAMIKOUHOMONTH=VAL(DATEOFRIKKAMIKOUHO$(6:6))*10+VAL(DATEOFRIKKAMIKOUHO$(7:7))
LET RIKKAMIKOUHODAY=VAL(DATEOFRIKKAMIKOUHO$(9:9))*10+VAL(DATEOFRIKKAMIKOUHO$(10:10))
LET TM=YMDT2JD(YEAR,RIKKAMIKOUHOMONTH,RIKKAMIKOUHODAY, 0, 0, 0)
IF RIKKAMIKOUHOMONTH=1 OR RIKKAMIKOUHOMONTH=2 THEN LET ye=YEAR-1
IF RIKKAMIKOUHOMONTH=1 THEN LET mo=13
IF RIKKAMIKOUHOMONTH=2 THEN LET mo=14
IF RIKKAMIKOUHOMONTH<>1 AND RIKKAMIKOUHOMONTH<>2 THEN LET ye=YEAR
IF RIKKAMIKOUHOMONTH<>1 AND RIKKAMIKOUHOMONTH<>2 THEN LET mo=RIKKAMIKOUHOMONTH
LET c=INT(ye/100)
LET n=ye-INT(ye/100)*100
LET JYUUNISHIJOUYOKEI=MOD(INT(44.25*c)+INT(5.25*n)+INT(30.6*(mo+1))+6+RIKKAMIKOUHODAY,12)
LET ETOMOJIWATASHI$=CALC_ETO61$(JYUUNISHIJOUYOKEI) !' IF RIKKAMIKOUHODAY>SD THENは不要かも?結局削除した。
IF ETOMOJIWATASHI$(2:2)="巳" THEN LET RIKKAMIMONTH=RIKKAMIKOUHOMONTH
IF ETOMOJIWATASHI$(2:2)="巳" THEN LET RIKKAMIDAY=RIKKAMIKOUHODAY
IF ETOMOJIWATASHI$(2:2)="巳" THEN EXIT FOR
NEXT JMI !' Jではなく、JMIとする。
LET JDBOUSHU=YMDT2JD(YEAR, VAL(SEKKI24$(10, 0)(6:6))*10+VAL(SEKKI24$(10, 0)(7:7)), VAL(SEKKI24$(10, 0)(9:9))*10+VAL(SEKKI24$(10, 0)(10:10)), 0, 0, 0)
FOR JUMA=1 TO 12 !' Jではなく、JUMAとする。
LET JDBOUSHUUMAKOUHO=JDBOUSHU+JUMA !' Jではなく、JUMAとする。
LET DATEOFBOUSHUUMAKOUHO$=JD2YMDT$(JDBOUSHUUMAKOUHO)
LET BOUSHUUMAKOUHOMONTH=VAL(DATEOFBOUSHUUMAKOUHO$(6:6))*10+VAL(DATEOFBOUSHUUMAKOUHO$(7:7))
LET BOUSHUUMAKOUHODAY=VAL(DATEOFBOUSHUUMAKOUHO$(9:9))*10+VAL(DATEOFBOUSHUUMAKOUHO$(10:10))
LET TM=YMDT2JD(YEAR,BOUSHUUMAKOUHOMONTH,BOUSHUUMAKOUHODAY, 0, 0, 0)
IF BOUSHUUMAKOUHOMONTH=1 OR BOUSHUUMAKOUHOMONTH=2 THEN LET ye=YEAR-1
IF BOUSHUUMAKOUHOMONTH=1 THEN LET mo=13
IF BOUSHUUMAKOUHOMONTH=2 THEN LET mo=14
IF BOUSHUUMAKOUHOMONTH<>1 AND BOUSHUUMAKOUHOMONTH<>2 THEN LET ye=YEAR
IF BOUSHUUMAKOUHOMONTH<>1 AND BOUSHUUMAKOUHOMONTH<>2 THEN LET mo=BOUSHUUMAKOUHOMONTH
LET c=INT(ye/100)
LET n=ye-INT(ye/100)*100
LET JYUUNISHIJOUYOKEI=MOD(INT(44.25*c)+INT(5.25*n)+INT(30.6*(mo+1))+6+BOUSHUUMAKOUHODAY,12)
LET ETOMOJIWATASHI$=CALC_ETO61$(JYUUNISHIJOUYOKEI) !' IF BOUSHUUMAKOUHODAY>SD THENは不要かも?結局削除した。
IF ETOMOJIWATASHI$(2:2)="午" THEN LET BOUSHUUMAMONTH=BOUSHUUMAKOUHOMONTH
IF ETOMOJIWATASHI$(2:2)="午" THEN LET BOUSHUUMADAY=BOUSHUUMAKOUHODAY
IF ETOMOJIWATASHI$(2:2)="午" THEN EXIT FOR
NEXT JUMA !' Jではなく、JUMAとする。
LET JDSHOUSHO=YMDT2JD(YEAR, VAL(SEKKI24$(12, 0)(6:6))*10+VAL(SEKKI24$(12, 0)(7:7)), VAL(SEKKI24$(12, 0)(9:9))*10+VAL(SEKKI24$(12, 0)(10:10)), 0, 0, 0)
FOR JHITUJI=1 TO 12 !' Jではなく、JHITUJIとする。
LET JDSHOUSHOHITUJIKOUHO=JDSHOUSHO+JHITUJI !' Jではなく、JHITUJIとする。
LET DATEOFSHOUSHOHITUJIKOUHO$=JD2YMDT$(JDSHOUSHOHITUJIKOUHO)
LET SHOUSHOHITUJIKOUHOMONTH=VAL(DATEOFSHOUSHOHITUJIKOUHO$(6:6))*10+VAL(DATEOFSHOUSHOHITUJIKOUHO$(7:7))
LET SHOUSHOHITUJIKOUHODAY=VAL(DATEOFSHOUSHOHITUJIKOUHO$(9:9))*10+VAL(DATEOFSHOUSHOHITUJIKOUHO$(10:10))
LET TM=YMDT2JD(YEAR,SHOUSHOHITUJIKOUHOMONTH,SHOUSHOHITUJIKOUHODAY, 0, 0, 0)
IF SHOUSHOHITUJIKOUHOMONTH=1 OR SHOUSHOHITUJIKOUHOMONTH=2 THEN LET ye=YEAR-1
IF SHOUSHOHITUJIKOUHOMONTH=1 THEN LET mo=13
IF SHOUSHOHITUJIKOUHOMONTH=2 THEN LET mo=14
IF SHOUSHOHITUJIKOUHOMONTH<>1 AND SHOUSHOHITUJIKOUHOMONTH<>2 THEN LET ye=YEAR
IF SHOUSHOHITUJIKOUHOMONTH<>1 AND SHOUSHOHITUJIKOUHOMONTH<>2 THEN LET mo=SHOUSHOHITUJIKOUHOMONTH
LET c=INT(ye/100)
LET n=ye-INT(ye/100)*100
LET JYUUNISHIJOUYOKEI=MOD(INT(44.25*c)+INT(5.25*n)+INT(30.6*(mo+1))+6+SHOUSHOHITUJIKOUHODAY,12)
LET ETOMOJIWATASHI$=CALC_ETO61$(JYUUNISHIJOUYOKEI) !' IF SHOUSHOHITUJIKOUHODAY>SD THENは不要かも?結局削除した。
IF ETOMOJIWATASHI$(2:2)="未" THEN LET SHOUSHOHITUJIMONTH=SHOUSHOHITUJIKOUHOMONTH
IF ETOMOJIWATASHI$(2:2)="未" THEN LET SHOUSHOHITUJIDAY=SHOUSHOHITUJIKOUHODAY
IF ETOMOJIWATASHI$(2:2)="未" THEN EXIT FOR
NEXT JHITUJI !' Jではなく、JHITUJIとする。
LET JDRISSHUU=YMDT2JD(YEAR, VAL(SEKKI24$(14, 0)(6:6))*10+VAL(SEKKI24$(14, 0)(7:7)), VAL(SEKKI24$(14, 0)(9:9))*10+VAL(SEKKI24$(14, 0)(10:10)), 0, 0, 0)
FOR JSARU=1 TO 12 !' Jではなく、JSARUとする。
LET JDRISSHUUSARUKOUHO=JDRISSHUU+JSARU !' Jではなく、JSARUとする。
LET DATEOFRISSHUUSARUKOUHO$=JD2YMDT$(JDRISSHUUSARUKOUHO)
LET RISSHUUSARUKOUHOMONTH=VAL(DATEOFRISSHUUSARUKOUHO$(6:6))*10+VAL(DATEOFRISSHUUSARUKOUHO$(7:7))
LET RISSHUUSARUKOUHODAY=VAL(DATEOFRISSHUUSARUKOUHO$(9:9))*10+VAL(DATEOFRISSHUUSARUKOUHO$(10:10))
LET TM=YMDT2JD(YEAR,RISSHUUSARUKOUHOMONTH,RISSHUUSARUKOUHODAY, 0, 0, 0)
IF RISSHUUSARUKOUHOMONTH=1 OR RISSHUUSARUKOUHOMONTH=2 THEN LET ye=YEAR-1
IF RISSHUUSARUKOUHOMONTH=1 THEN LET mo=13
IF RISSHUUSARUKOUHOMONTH=2 THEN LET mo=14
IF RISSHUUSARUKOUHOMONTH<>1 AND RISSHUUSARUKOUHOMONTH<>2 THEN LET ye=YEAR
IF RISSHUUSARUKOUHOMONTH<>1 AND RISSHUUSARUKOUHOMONTH<>2 THEN LET mo=RISSHUUSARUKOUHOMONTH
LET c=INT(ye/100)
LET n=ye-INT(ye/100)*100
LET JYUUNISHIJOUYOKEI=MOD(INT(44.25*c)+INT(5.25*n)+INT(30.6*(mo+1))+6+RISSHUUSARUKOUHODAY,12)
LET ETOMOJIWATASHI$=CALC_ETO61$(JYUUNISHIJOUYOKEI) !' IF RISSHUUSARUKOUHODAY>SD THENは不要かも?結局削除した。
IF ETOMOJIWATASHI$(2:2)="申" THEN LET RISSHUUSARUMONTH=RISSHUUSARUKOUHOMONTH
IF ETOMOJIWATASHI$(2:2)="申" THEN LET RISSHUUSARUDAY=RISSHUUSARUKOUHODAY
IF ETOMOJIWATASHI$(2:2)="申" THEN EXIT FOR
NEXT JSARU !' Jではなく、JSARUとする。
LET JDHAKURO=YMDT2JD(YEAR, VAL(SEKKI24$(16, 0)(6:6))*10+VAL(SEKKI24$(16, 0)(7:7)), VAL(SEKKI24$(16, 0)(9:9))*10+VAL(SEKKI24$(16, 0)(10:10)), 0, 0, 0)
FOR JTORI=1 TO 12 !' Jではなく、JTORIとする。
LET JDHAKUROTORIKOUHO=JDHAKURO+JTORI !' Jではなく、JTORIとする。
LET DATEOFHAKUROTORIKOUHO$=JD2YMDT$(JDHAKUROTORIKOUHO)
LET HAKUROTORIKOUHOMONTH=VAL(DATEOFHAKUROTORIKOUHO$(6:6))*10+VAL(DATEOFHAKUROTORIKOUHO$(7:7))
LET HAKUROTORIKOUHODAY=VAL(DATEOFHAKUROTORIKOUHO$(9:9))*10+VAL(DATEOFHAKUROTORIKOUHO$(10:10))
LET TM=YMDT2JD(YEAR,HAKUROTORIKOUHOMONTH,HAKUROTORIKOUHODAY, 0, 0, 0)
IF HAKUROTORIKOUHOMONTH=1 OR HAKUROTORIKOUHOMONTH=2 THEN LET ye=YEAR-1
IF HAKUROTORIKOUHOMONTH=1 THEN LET mo=13
IF HAKUROTORIKOUHOMONTH=2 THEN LET mo=14
IF HAKUROTORIKOUHOMONTH<>1 AND HAKUROTORIKOUHOMONTH<>2 THEN LET ye=YEAR
IF HAKUROTORIKOUHOMONTH<>1 AND HAKUROTORIKOUHOMONTH<>2 THEN LET mo=HAKUROTORIKOUHOMONTH
LET c=INT(ye/100)
LET n=ye-INT(ye/100)*100
LET JYUUNISHIJOUYOKEI=MOD(INT(44.25*c)+INT(5.25*n)+INT(30.6*(mo+1))+6+HAKUROTORIKOUHODAY,12)
LET ETOMOJIWATASHI$=CALC_ETO61$(JYUUNISHIJOUYOKEI) !' IF RISSHUUSARUKOUHODAY>SD THENは不要かも?結局削除した。
IF ETOMOJIWATASHI$(2:2)="酉" THEN LET HAKUROTORIMONTH=HAKUROTORIKOUHOMONTH
IF ETOMOJIWATASHI$(2:2)="酉" THEN LET HAKUROTORIDAY=HAKUROTORIKOUHODAY
IF ETOMOJIWATASHI$(2:2)="酉" THEN EXIT FOR
NEXT JTORI !' Jではなく、JTORIとする。
LET JDKANNRO=YMDT2JD(YEAR, VAL(SEKKI24$(18, 0)(6:6))*10+VAL(SEKKI24$(18, 0)(7:7)), VAL(SEKKI24$(18, 0)(9:9))*10+VAL(SEKKI24$(18, 0)(10:10)), 0, 0, 0)
FOR JINU=1 TO 12 !' Jではなく、JINUとする。
LET JDKANNROINUKOUHO=JDKANNRO+JINU !' Jではなく、JINUとする。転記ミス発見。LET JDKANNROINUKOUHO=JDHAKURO+JINUをLET JDKANNROINUKOUHO=JDKANNRO+JINUに直した。
LET DATEOFKANNROINUKOUHO$=JD2YMDT$(JDKANNROINUKOUHO)
LET KANNROINUKOUHOMONTH=VAL(DATEOFKANNROINUKOUHO$(6:6))*10+VAL(DATEOFKANNROINUKOUHO$(7:7))
LET KANNROINUKOUHODAY=VAL(DATEOFKANNROINUKOUHO$(9:9))*10+VAL(DATEOFKANNROINUKOUHO$(10:10))
LET TM=YMDT2JD(YEAR,KANNROINUKOUHOMONTH,KANNROINUKOUHODAY, 0, 0, 0)
IF KANNROINUKOUHOMONTH=1 OR KANNROINUKOUHOMONTH=2 THEN LET ye=YEAR-1
IF KANNROINUKOUHOMONTH=1 THEN LET mo=13
IF KANNROINUKOUHOMONTH=2 THEN LET mo=14
IF KANNROINUKOUHOMONTH<>1 AND KANNROINUKOUHOMONTH<>2 THEN LET ye=YEAR
IF KANNROINUKOUHOMONTH<>1 AND KANNROINUKOUHOMONTH<>2 THEN LET mo=KANNROINUKOUHOMONTH
LET c=INT(ye/100)
LET n=ye-INT(ye/100)*100
LET JYUUNISHIJOUYOKEI=MOD(INT(44.25*c)+INT(5.25*n)+INT(30.6*(mo+1))+6+KANNROINUKOUHODAY,12)
LET ETOMOJIWATASHI$=CALC_ETO61$(JYUUNISHIJOUYOKEI) !' IF KANNROINUKOUHODAY>SD THENは不要かも?結局削除した。
IF ETOMOJIWATASHI$(2:2)="戌" THEN LET KANNROINUMONTH=KANNROINUKOUHOMONTH
IF ETOMOJIWATASHI$(2:2)="戌" THEN LET KANNROINUDAY=KANNROINUKOUHODAY
IF ETOMOJIWATASHI$(2:2)="戌" THEN EXIT FOR
NEXT JINU !' Jではなく、JINUとする。
LET JDRITTOU=YMDT2JD(YEAR, VAL(SEKKI24$(20, 0)(6:6))*10+VAL(SEKKI24$(20, 0)(7:7)), VAL(SEKKI24$(20, 0)(9:9))*10+VAL(SEKKI24$(20, 0)(10:10)), 0, 0, 0)
FOR JII=1 TO 12 !' Jではなく、JIIとする。
LET JDRITTOUIIKOUHO=JDRITTOU+JII !' Jではなく、JIIとする。
LET DATEOFRITTOUIIKOUHO$=JD2YMDT$(JDRITTOUIIKOUHO)
LET RITTOUIIKOUHOMONTH=VAL(DATEOFRITTOUIIKOUHO$(6:6))*10+VAL(DATEOFRITTOUIIKOUHO$(7:7))
LET RITTOUIIKOUHODAY=VAL(DATEOFRITTOUIIKOUHO$(9:9))*10+VAL(DATEOFRITTOUIIKOUHO$(10:10))
LET TM=YMDT2JD(YEAR,RITTOUIIKOUHOMONTH,RITTOUIIKOUHODAY, 0, 0, 0)
IF RITTOUIIKOUHOMONTH=1 OR RITTOUIIKOUHOMONTH=2 THEN LET ye=YEAR-1
IF RITTOUIIKOUHOMONTH=1 THEN LET mo=13
IF RITTOUIIKOUHOMONTH=2 THEN LET mo=14
IF RITTOUIIKOUHOMONTH<>1 AND RITTOUIIKOUHOMONTH<>2 THEN LET ye=YEAR
IF RITTOUIIKOUHOMONTH<>1 AND RITTOUIIKOUHOMONTH<>2 THEN LET mo=RITTOUIIKOUHOMONTH
LET c=INT(ye/100)
LET n=ye-INT(ye/100)*100
LET JYUUNISHIJOUYOKEI=MOD(INT(44.25*c)+INT(5.25*n)+INT(30.6*(mo+1))+6+RITTOUIIKOUHODAY,12)
LET ETOMOJIWATASHI$=CALC_ETO61$(JYUUNISHIJOUYOKEI) !' IF RITTOUIIKOUHODAY>SD THENは不要かも?結局削除した。
IF ETOMOJIWATASHI$(2:2)="亥" THEN LET RITTOUIIMONTH=RITTOUIIKOUHOMONTH
IF ETOMOJIWATASHI$(2:2)="亥" THEN LET RITTOUIIDAY=RITTOUIIKOUHODAY
IF ETOMOJIWATASHI$(2:2)="亥" THEN EXIT FOR
NEXT JII !' Jではなく、JIIとする。
LET JDDAISETSU=YMDT2JD(YEAR, VAL(SEKKI24$(22, 0)(6:6))*10+VAL(SEKKI24$(22, 0)(7:7)), VAL(SEKKI24$(22, 0)(9:9))*10+VAL(SEKKI24$(22, 0)(10:10)), 0, 0, 0)
FOR JNE=1 TO 12 !' Jではなく、JNEとする。
LET JDDAISETSUNEKOUHO=JDDAISETSU+JNE !' Jではなく、JNEとする。
LET DATEOFDAISETSUNEKOUHO$=JD2YMDT$(JDDAISETSUNEKOUHO)
LET DAISETSUNEKOUHOMONTH=VAL(DATEOFDAISETSUNEKOUHO$(6:6))*10+VAL(DATEOFDAISETSUNEKOUHO$(7:7))
LET DAISETSUNEKOUHODAY=VAL(DATEOFDAISETSUNEKOUHO$(9:9))*10+VAL(DATEOFDAISETSUNEKOUHO$(10:10))
LET TM=YMDT2JD(YEAR,DAISETSUNEKOUHOMONTH,DAISETSUNEKOUHODAY, 0, 0, 0)
IF DAISETSUNEKOUHOMONTH=1 OR DAISETSUNEKOUHOMONTH=2 THEN LET ye=YEAR-1
IF DAISETSUNEKOUHOMONTH=1 THEN LET mo=13
IF DAISETSUNEKOUHOMONTH=2 THEN LET mo=14
IF DAISETSUNEKOUHOMONTH<>1 AND DAISETSUNEKOUHOMONTH<>2 THEN LET ye=YEAR
IF DAISETSUNEKOUHOMONTH<>1 AND DAISETSUNEKOUHOMONTH<>2 THEN LET mo=DAISETSUNEKOUHOMONTH
LET c=INT(ye/100)
LET n=ye-INT(ye/100)*100
LET JYUUNISHIJOUYOKEI=MOD(INT(44.25*c)+INT(5.25*n)+INT(30.6*(mo+1))+6+DAISETSUNEKOUHODAY,12)
LET ETOMOJIWATASHI$=CALC_ETO61$(JYUUNISHIJOUYOKEI) !' IF DAISETSUNEKOUHODAY>SD THENは不要かも?結局削除した。
IF ETOMOJIWATASHI$(2:2)="子" THEN LET DAISETSUNEMONTH=DAISETSUNEKOUHOMONTH
IF ETOMOJIWATASHI$(2:2)="子" THEN LET DAISETSUNEDAY=DAISETSUNEKOUHODAY
IF ETOMOJIWATASHI$(2:2)="子" THEN EXIT FOR
NEXT JNE !' Jではなく、JNEとする。
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
DIM TYOKUOF12$(42)
IF MONTH=SHOUKANNUSHIMONTH AND I <SHOUKANNUSHIDAY-JUSHI AND I>0 THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-SHOUKANNUSHIDAY+1,12))
IF MONTH=SHOUKANNUSHIMONTH AND I=>SHOUKANNUSHIDAY-JUSHI AND I=<DD(SHOUKANNUSHIMONTH) THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-SHOUKANNUSHIDAY,12))
IF MONTH=RISSHUNNTORAMONTH AND I <RISSHUNNTORADAY AND I>0 THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-SHOUKANNUSHIDAY +DD(SHOUKANNUSHIMONTH),12))
IF MONTH=RISSHUNNTORAMONTH AND I=>RISSHUNNTORADAY-JTORA AND I<RISSHUNNTORADAY THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-SHOUKANNUSHIDAY +DD(SHOUKANNUSHIMONTH)-1,12))
IF MONTH=RISSHUNNTORAMONTH AND I=>RISSHUNNTORADAY THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-RISSHUNNTORADAY,12))
IF MONTH=KEICHITUUUMONTH AND I <KEICHITUUUDAY AND I>0 THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-RISSHUNNTORADAY +DD(RISSHUNNTORAMONTH),12))
IF MONTH=KEICHITUUUMONTH AND I=>KEICHITUUUDAY-JUU AND I<KEICHITUUUDAY THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-RISSHUNNTORADAY +DD(RISSHUNNTORAMONTH)-1,12))
IF MONTH=KEICHITUUUMONTH AND I=>KEICHITUUUDAY THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-KEICHITUUUDAY,12))
IF MONTH=SEIMEITATSUMONTH AND I <SEIMEITATSUDAY AND I>0 THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-KEICHITUUUDAY +DD(KEICHITUUUMONTH),12))
IF MONTH=SEIMEITATSUMONTH AND I=>SEIMEITATSUDAY-JTATSU AND I<SEIMEITATSUDAY THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-KEICHITUUUDAY +DD(KEICHITUUUMONTH)-1,12))
IF MONTH=SEIMEITATSUMONTH AND I=>SEIMEITATSUDAY THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-SEIMEITATSUDAY,12))
IF MONTH=RIKKAMIMONTH AND I <RIKKAMIDAY AND I>0 THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-SEIMEITATSUDAY +DD(SEIMEITATSUMONTH),12))
IF MONTH=RIKKAMIMONTH AND I=>RIKKAMIDAY-JMI AND I<RIKKAMIDAY THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-SEIMEITATSUDAY +DD(SEIMEITATSUMONTH)-1,12))
IF MONTH=RIKKAMIMONTH AND I=>RIKKAMIDAY THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-RIKKAMIDAY,12))
IF MONTH=BOUSHUUMAMONTH AND I <BOUSHUUMADAY AND I>0 THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-RIKKAMIDAY +DD(RIKKAMIMONTH),12))
IF MONTH=BOUSHUUMAMONTH AND I=>BOUSHUUMADAY-JUMA AND I<BOUSHUUMADAY THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-RIKKAMIDAY +DD(RIKKAMIMONTH)-1,12))
IF MONTH=BOUSHUUMAMONTH AND I=>BOUSHUUMADAY THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-BOUSHUUMADAY,12))
IF MONTH=SHOUSHOHITUJIMONTH AND I <SHOUSHOHITUJIDAY AND I>0 THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-BOUSHUUMADAY +DD(BOUSHUUMAMONTH),12))
IF MONTH=SHOUSHOHITUJIMONTH AND I=>SHOUSHOHITUJIDAY-JHITUJI AND I<SHOUSHOHITUJIDAY THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-BOUSHUUMADAY +DD(BOUSHUUMAMONTH)-1,12))
IF MONTH=SHOUSHOHITUJIMONTH AND I=>SHOUSHOHITUJIDAY THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-SHOUSHOHITUJIDAY,12))
IF MONTH=RISSHUUSARUMONTH AND I <RISSHUUSARUDAY AND I>0 THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-SHOUSHOHITUJIDAY +DD(SHOUSHOHITUJIMONTH),12))
IF MONTH=RISSHUUSARUMONTH AND I=>RISSHUUSARUDAY-JSARU AND I<RISSHUUSARUDAY THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-SHOUSHOHITUJIDAY +DD(SHOUSHOHITUJIMONTH)-1,12)) !' RISSHUUSARUDAY-JSARU =< I < RISSHUUSARUDAY を満たす日だけはRISSHUUSARUDAY-JSARUの日はRISSHUUSARUDAY-JSARU-1の十二直を一日だけ繰り返したあとで、さらに規則を続ける。
IF MONTH=RISSHUUSARUMONTH AND I=>RISSHUUSARUDAY THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-RISSHUUSARUDAY,12))
IF MONTH=HAKUROTORIMONTH AND I <HAKUROTORIDAY AND I>0 THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-RISSHUUSARUDAY +DD(RISSHUUSARUMONTH),12))
IF MONTH=HAKUROTORIMONTH AND I=>HAKUROTORIDAY-JTORI AND I<HAKUROTORIDAY THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-RISSHUUSARUDAY +DD(RISSHUUSARUMONTH)-1,12))
IF MONTH=HAKUROTORIMONTH AND I=>HAKUROTORIDAY THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-HAKUROTORIDAY,12))
IF MONTH=KANNROINUMONTH AND I <KANNROINUDAY AND I>0 THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-HAKUROTORIDAY +DD(HAKUROTORIMONTH),12))
IF MONTH=KANNROINUMONTH AND I=>KANNROINUDAY-JINU AND I<KANNROINUDAY THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-HAKUROTORIDAY +DD(HAKUROTORIMONTH)-1,12))
IF MONTH=KANNROINUMONTH AND I=>KANNROINUDAY THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-KANNROINUDAY,12))
IF MONTH=RITTOUIIMONTH AND I <RITTOUIIDAY AND I>0 THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-KANNROINUDAY +DD(KANNROINUMONTH),12))
IF MONTH=RITTOUIIMONTH AND I=>RITTOUIIDAY-JII AND I<RITTOUIIDAY THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-KANNROINUDAY +DD(KANNROINUMONTH)-1,12))
IF MONTH=RITTOUIIMONTH AND I=>RITTOUIIDAY THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-RITTOUIIDAY,12))
IF MONTH=DAISETSUNEMONTH AND I <DAISETSUNEDAY AND I>0 THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-RITTOUIIDAY +DD(RITTOUIIMONTH),12))
IF MONTH=DAISETSUNEMONTH AND I=>DAISETSUNEDAY-JNE AND I<DAISETSUNEDAY THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-RITTOUIIDAY +DD(RITTOUIIMONTH)-1,12))
IF MONTH=DAISETSUNEMONTH AND I=>DAISETSUNEDAY THEN LET TYOKUOF12$(I)=TYOKU12$(MOD(I-DAISETSUNEDAY,12))
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
SET TEXT HEIGHT HEIGHT*.2
CALL MOON(XS+XX+HEIGHT*.6,YS+YY+HEIGHT*.5,HEIGHT*.5,QMAGENOON-.5,QILLUMI/100)
CALL SYMBOL(XS+XX,YS+YY+HEIGHT*.25,COL$,QROKUYOU$&" "&N$&STR$(QMONTH)&"/"&STR$(QDAY))
CALL SYMBOL(XS+XX,YS+YY+HEIGHT*.5,COL$,A$)
CALL SYMBOL(XS+XX,YS+YY+HEIGHT*.75,COL$,B$)
CALL SYMBOL(XS+XX,YS+YY+HEIGHT*1.0,COL$,TYOKUOF12$(I))
CALL SYMBOL(XS+XX,YS+YY+HEIGHT*1.25,COL$,SHUKU28$(NIJYUUHASSHUKU))
IF Z$<>"" THEN CALL SYMBOL(XS+XX,YS+YY+HEIGHT*1.5,"GREEN",Z$)
FOR K=0 TO 23
IF VAL(SEKKI24$(K, 0)(6:7))=MONTH AND VAL(SEKKI24$(K, 0)(9:10))=I THEN
IF Z$<>"" THEN
CALL SYMBOL(XS+XX,YS+YY+HEIGHT*1.75,"MAGENTA",SEKKI24$(K, 1))
LET FL=1
ELSE
CALL SYMBOL(XS+XX,YS+YY+HEIGHT*1.5,"MAGENTA",SEKKI24$(K, 1))
LET FL=2
END IF
EXIT FOR
END IF
NEXT K
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
FOR K=0 TO 23
IF VAL(SEKKI24$(K, 0)(6:7))=MONTH THEN
IF VAL(SEKKI24$(K, 0)(9:10))= I THEN
IF MOD(I+R-1,7)=0 THEN
PRINT USING ">######## ####>################>########## --.# --.#>######>####>####>####>########>######>########>##########" : RIGHT$(" "&MONTH$,2)&"月"&RIGHT$(" "&STR$(I),2)&"日","日",Z$,RIGHT$(" "&N$&STR$(QMONTH),3)&"月"&RIGHT$(" "&STR$(QDAY),2)&"日",QMAGE,QMAGENOON,QILLUMI,QMPHASE,QROKUYOU$,C$,B$,TYOKUOF12$(I),SHUKU28$(NIJYUUHASSHUKU),SEKKIOF24$(I)
END IF
IF MOD(I+R-1,7)=1 THEN
PRINT USING ">######## ####>################>########## --.# --.#>######>####>####>####>########>######>########>##########" : RIGHT$(" "&MONTH$,2)&"月"&RIGHT$(" "&STR$(I),2)&"日","月",Z$,RIGHT$(" "&N$&STR$(QMONTH),3)&"月"&RIGHT$(" "&STR$(QDAY),2)&"日",QMAGE,QMAGENOON,QILLUMI,QMPHASE,QROKUYOU$,C$,B$,TYOKUOF12$(I),SHUKU28$(NIJYUUHASSHUKU),SEKKIOF24$(I)
END IF
IF MOD(I+R-1,7)=2 THEN
PRINT USING ">######## ####>################>########## --.# --.#>######>####>####>####>########>######>########>##########" : RIGHT$(" "&MONTH$,2)&"月"&RIGHT$(" "&STR$(I),2)&"日","火",Z$,RIGHT$(" "&N$&STR$(QMONTH),3)&"月"&RIGHT$(" "&STR$(QDAY),2)&"日",QMAGE,QMAGENOON,QILLUMI,QMPHASE,QROKUYOU$,C$,B$,TYOKUOF12$(I),SHUKU28$(NIJYUUHASSHUKU),SEKKIOF24$(I)
END IF
IF MOD(I+R-1,7)=3 THEN
PRINT USING ">######## ####>################>########## --.# --.#>######>####>####>####>########>######>########>##########" : RIGHT$(" "&MONTH$,2)&"月"&RIGHT$(" "&STR$(I),2)&"日","水",Z$,RIGHT$(" "&N$&STR$(QMONTH),3)&"月"&RIGHT$(" "&STR$(QDAY),2)&"日",QMAGE,QMAGENOON,QILLUMI,QMPHASE,QROKUYOU$,C$,B$,TYOKUOF12$(I),SHUKU28$(NIJYUUHASSHUKU),SEKKIOF24$(I)
END IF
IF MOD(I+R-1,7)=4 THEN
PRINT USING ">######## ####>################>########## --.# --.#>######>####>####>####>########>######>########>##########" : RIGHT$(" "&MONTH$,2)&"月"&RIGHT$(" "&STR$(I),2)&"日","木",Z$,RIGHT$(" "&N$&STR$(QMONTH),3)&"月"&RIGHT$(" "&STR$(QDAY),2)&"日",QMAGE,QMAGENOON,QILLUMI,QMPHASE,QROKUYOU$,C$,B$,TYOKUOF12$(I),SHUKU28$(NIJYUUHASSHUKU),SEKKIOF24$(I)
END IF
IF MOD(I+R-1,7)=5 THEN
PRINT USING ">######## ####>################>########## --.# --.#>######>####>####>####>########>######>########>##########" : RIGHT$(" "&MONTH$,2)&"月"&RIGHT$(" "&STR$(I),2)&"日","金",Z$,RIGHT$(" "&N$&STR$(QMONTH),3)&"月"&RIGHT$(" "&STR$(QDAY),2)&"日",QMAGE,QMAGENOON,QILLUMI,QMPHASE,QROKUYOU$,C$,B$,TYOKUOF12$(I),SHUKU28$(NIJYUUHASSHUKU),SEKKIOF24$(I)
END IF
IF MOD(I+R-1,7)=6 THEN
PRINT USING ">######## ####>################>########## --.# --.#>######>####>####>####>########>######>########>##########" : RIGHT$(" "&MONTH$,2)&"月"&RIGHT$(" "&STR$(I),2)&"日","土",Z$,RIGHT$(" "&N$&STR$(QMONTH),3)&"月"&RIGHT$(" "&STR$(QDAY),2)&"日",QMAGE,QMAGENOON,QILLUMI,QMPHASE,QROKUYOU$,C$,B$,TYOKUOF12$(I),SHUKU28$(NIJYUUHASSHUKU),SEKKIOF24$(I)
END IF
ELSE
IF MOD(I+R-1,7)=0 THEN
PRINT USING ">######## ####>################>########## --.# --.#>######>####>####>####>########>######>########>##########" : RIGHT$(" "&MONTH$,2)&"月"&RIGHT$(" "&STR$(I),2)&"日","日",Z$,RIGHT$(" "&N$&STR$(QMONTH),3)&"月"&RIGHT$(" "&STR$(QDAY),2)&"日",QMAGE,QMAGENOON,QILLUMI,QMPHASE,QROKUYOU$,C$,B$,TYOKUOF12$(I),SHUKU28$(NIJYUUHASSHUKU),SEKKIOF24$(I)
END IF
IF MOD(I+R-1,7)=1 THEN
PRINT USING ">######## ####>################>########## --.# --.#>######>####>####>####>########>######>########>##########" : RIGHT$(" "&MONTH$,2)&"月"&RIGHT$(" "&STR$(I),2)&"日","月",Z$,RIGHT$(" "&N$&STR$(QMONTH),3)&"月"&RIGHT$(" "&STR$(QDAY),2)&"日",QMAGE,QMAGENOON,QILLUMI,QMPHASE,QROKUYOU$,C$,B$,TYOKUOF12$(I),SHUKU28$(NIJYUUHASSHUKU),SEKKIOF24$(I)
END IF
IF MOD(I+R-1,7)=2 THEN
PRINT USING ">######## ####>################>########## --.# --.#>######>####>####>####>########>######>########>##########" : RIGHT$(" "&MONTH$,2)&"月"&RIGHT$(" "&STR$(I),2)&"日","火",Z$,RIGHT$(" "&N$&STR$(QMONTH),3)&"月"&RIGHT$(" "&STR$(QDAY),2)&"日",QMAGE,QMAGENOON,QILLUMI,QMPHASE,QROKUYOU$,C$,B$,TYOKUOF12$(I),SHUKU28$(NIJYUUHASSHUKU),SEKKIOF24$(I)
END IF
IF MOD(I+R-1,7)=3 THEN
PRINT USING ">######## ####>################>########## --.# --.#>######>####>####>####>########>######>########>##########" : RIGHT$(" "&MONTH$,2)&"月"&RIGHT$(" "&STR$(I),2)&"日","水",Z$,RIGHT$(" "&N$&STR$(QMONTH),3)&"月"&RIGHT$(" "&STR$(QDAY),2)&"日",QMAGE,QMAGENOON,QILLUMI,QMPHASE,QROKUYOU$,C$,B$,TYOKUOF12$(I),SHUKU28$(NIJYUUHASSHUKU),SEKKIOF24$(I)
END IF
IF MOD(I+R-1,7)=4 THEN
PRINT USING ">######## ####>################>########## --.# --.#>######>####>####>####>########>######>########>##########" : RIGHT$(" "&MONTH$,2)&"月"&RIGHT$(" "&STR$(I),2)&"日","木",Z$,RIGHT$(" "&N$&STR$(QMONTH),3)&"月"&RIGHT$(" "&STR$(QDAY),2)&"日",QMAGE,QMAGENOON,QILLUMI,QMPHASE,QROKUYOU$,C$,B$,TYOKUOF12$(I),SHUKU28$(NIJYUUHASSHUKU),SEKKIOF24$(I)
END IF
IF MOD(I+R-1,7)=5 THEN
PRINT USING ">######## ####>################>########## --.# --.#>######>####>####>####>########>######>########>##########" : RIGHT$(" "&MONTH$,2)&"月"&RIGHT$(" "&STR$(I),2)&"日","金",Z$,RIGHT$(" "&N$&STR$(QMONTH),3)&"月"&RIGHT$(" "&STR$(QDAY),2)&"日",QMAGE,QMAGENOON,QILLUMI,QMPHASE,QROKUYOU$,C$,B$,TYOKUOF12$(I),SHUKU28$(NIJYUUHASSHUKU),SEKKIOF24$(I)
END IF
IF MOD(I+R-1,7)=6 THEN
PRINT USING ">######## ####>################>########## --.# --.#>######>####>####>####>########>######>########>##########" : RIGHT$(" "&MONTH$,2)&"月"&RIGHT$(" "&STR$(I),2)&"日","土",Z$,RIGHT$(" "&N$&STR$(QMONTH),3)&"月"&RIGHT$(" "&STR$(QDAY),2)&"日",QMAGE,QMAGENOON,QILLUMI,QMPHASE,QROKUYOU$,C$,B$,TYOKUOF12$(I),SHUKU28$(NIJYUUHASSHUKU),SEKKIOF24$(I)
END IF
END IF
EXIT FOR
END IF
NEXT K
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
IF QMPHASE=14 THEN
LET S$="満月"
ELSEIF QMPHASE=0 THEN
LET S$="新月"
ELSE
!'LET S$=USING$("##.#",QILLUMI)&"%"
LET S$=""
END IF
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
IF S$<>"" THEN
IF Z$="" AND FL<>2 THEN
CALL SYMBOL(XS+XX,YS+YY+HEIGHT*1.6,"BLUE",S$)
ELSEIF FL<>1 THEN
CALL SYMBOL(XS+XX,YS+YY+HEIGHT*1.8,"BLUE",S$)
ELSE
CALL SYMBOL(XS+XX,YS+YY+HEIGHT*2.0,"BLUE",S$)
END IF
END IF
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
LET XX=XX+XSIZE/8
IF MOD(R+I,7)=0 THEN
LET XX=0
LET YY=YY+YSIZE/8
END IF
NEXT I
END
EXTERNAL SUB GINIT(XSIZE,YSIZE)
SET BITMAP SIZE XSIZE,YSIZE
SET WINDOW 0,XSIZE-1,YSIZE-1,0
SET POINT STYLE 1
SET COLOR MODE "REGULAR"
CLEAR
END SUB
EXTERNAL SUB SYMBOL(X,Y,COL$,A$)
SET TEXT COLOR COL$
PLOT TEXT,AT X,Y:A$
END SUB
EXTERNAL FUNCTION DAYCOLOR$(Y,M,N,R)
LET DAYCOLOR$="BLACK"
LET Z$=""
IF MOD(N+R,7)=1 THEN LET DAYCOLOR$="RED"
IF MOD(N+R,7)=0 THEN LET DAYCOLOR$="BLUE"
IF M=1 AND N=1 THEN
LET DAYCOLOR$="RED"
LET Z$="元日"
END IF
IF Y>=1973 AND M=1 AND N=2 AND MOD(N+R-1,7)=1 THEN
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
IF Y>=2000 THEN
IF M=1 AND ((R<=1 AND R+N=9) OR (R>1 AND R+N=16)) THEN
LET DAYCOLOR$="RED"
LET Z$="成人の日"
END IF
ELSE
IF M=1 AND N=15 THEN
LET DAYCOLOR$="RED"
LET Z$="成人の日"
END IF
IF Y>=1973 AND M=1 AND N=16 AND MOD(N+R-1,7)=1 THEN
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
END IF
IF M=2 AND N=11 THEN
LET DAYCOLOR$="RED"
LET Z$="建国記念の日"
END IF
IF Y>=1973 AND M=2 AND N=12 AND MOD(N+R-1,7)=1 THEN
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
IF Y>=2020 THEN
IF M=2 AND N=23 THEN
LET DAYCOLOR$="RED"
LET Z$="天皇誕生日"
END IF
IF M=2 AND N=24 AND MOD(N+R-1,7)=1 THEN
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
END IF
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
IF Y>=1900 AND Y<1980 THEN
IF M=3 AND N=INT(20.8357+0.242194*(Y-1980)-INT((Y-1983)/4)) THEN
LET DAYCOLOR$="RED"
LET Z$="春分の日"
END IF
IF Y>=1973 AND M=3 AND N=INT(20.8357+0.242194*(Y-1980)-INT((Y-1983)/4))+1 AND MOD(N+R-1,7)=1 THEN
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
IF M=9 AND N=INT(23.2588+0.242194*(Y-1980)-INT((Y-1983)/4)) THEN
LET DAYCOLOR$="RED"
LET Z$="秋分の日"
END IF
IF Y>=1973 AND M=9 AND N=INT(23.2588+0.242194*(Y-1980)-INT((Y-1983)/4))+1 AND MOD(N+R-1,7)=1 THEN
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
ELSEIF Y>=1980 AND Y<2100 THEN
IF M=3 AND N=INT(20.8431 + 0.242194 * (Y - 1980)) - INT((Y - 1980)/4) THEN
LET DAYCOLOR$="RED"
LET Z$="春分の日"
END IF
IF M=3 AND N=INT(20.8431 + 0.242194 * (Y - 1980)) - INT((Y - 1980)/4)+1 AND MOD(N+R-1,7)=1 THEN
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
IF M=9 AND N=INT(23.2488 + 0.242194 * (Y - 1980)) - INT((Y - 1980)/4) THEN
LET DAYCOLOR$="RED"
LET Z$="秋分の日"
END IF
IF M=9 AND N=INT(23.2488 + 0.242194 * (Y - 1980)) - INT((Y - 1980)/4)+1 AND MOD(N+R-1,7)=1 THEN
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
ELSEIF Y>=2100 AND Y<2150 THEN
IF M=3 AND N=INT(21.8510+0.242194*(Y-1980)-INT((Y-1980)/4)) THEN
LET DAYCOLOR$="RED"
LET Z$="春分の日"
END IF
IF M=3 AND N=INT(21.8510+0.242194*(Y-1980)-INT((Y-1980)/4))+1 AND MOD(N+R-1,7)=1 THEN
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
IF M=9 AND N=INT(24.2488+0.242194*(Y-1980)-INT((Y-1980)/4)) THEN
LET DAYCOLOR$="RED"
LET Z$="秋分の日"
END IF
IF M=9 AND N=INT(24.2488+0.242194*(Y-1980)-INT((Y-1980)/4))+1 AND MOD(N+R-1,7)=1 THEN
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
END IF
IF M=4 AND N=29 THEN
LET DAYCOLOR$="RED"
IF Y>=2007 THEN
LET Z$="昭和の日"
ELSEIF Y>=1989 AND Y<2007 THEN
LET Z$="みどりの日"
ELSEIF Y>1948 THEN
LET Z$="天皇誕生日"
END IF
END IF
IF Y>=1973 AND M=4 AND N=30 AND MOD(N+R-1,7)=1 THEN
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
IF Y=2019 AND M=4 AND N=30 AND MOD(N+R-1,7)<>1 THEN ! 令和元年昭和の日は2019年4月29日、即位の日は2019年5月1日。
LET DAYCOLOR$="RED" ! 間の2019年4月30日は振替休日でなくても公休日。
LET Z$="公休日"
END IF
IF Y=2019 AND M=5 AND N=1 THEN ! 令和元年即位の日は2019年5月1日。
LET DAYCOLOR$="RED"
LET Z$="即位の日"
END IF
IF Y=2019 AND M=5 AND N=2 AND MOD(N+R-1,7)=1 THEN ! 2019年5月2日が月曜なら振替休日とする。
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
IF Y=2019 AND M=5 AND N=2 AND MOD(N+R-1,7)<>1 THEN ! 令和元年即位の日は2019年5月1日、憲法記念日は西暦何年であっても5月3日。
LET DAYCOLOR$="RED" ! 間の2019年5月2日は振替休日でなくても公休日。
LET Z$="公休日"
END IF
IF M=5 AND N=3 THEN
LET DAYCOLOR$="RED"
LET Z$="憲法記念日"
END IF
IF Y>=2007 THEN
IF M=5 AND N=4 THEN
LET DAYCOLOR$="RED"
LET Z$="みどりの日"
END IF
ELSEIF Y>=1988 AND Y<2007 THEN
IF M=5 AND N=4 THEN
LET DAYCOLOR$="RED"
LET Z$="国民の休日"
END IF
END IF
IF M=5 AND N=5 THEN
LET DAYCOLOR$="RED"
LET Z$="こどもの日"
END IF
IF Y>=1973 AND M=5 AND N=6 AND MOD(N+R-1,7)=1 THEN
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
IF Y>=2003 THEN
IF Y=2021 AND M=7 AND N=22 THEN
LET DAYCOLOR$="RED"
LET Z$="海の日"
END IF
IF Y=2020 AND M=7 AND N=23 THEN
LET DAYCOLOR$="RED"
LET Z$="海の日"
END IF
IF Y<>2020 AND Y<>2021 AND M=7 AND ((R<=1 AND R+N=16) OR (R>1 AND R+N=23)) THEN
LET DAYCOLOR$="RED"
LET Z$="海の日"
END IF
ELSEIF Y>=1996 AND Y<2003 THEN
IF M=7 AND N=20 THEN
LET DAYCOLOR$="RED"
LET Z$="海の日"
END IF
IF M=7 AND N=21 AND MOD(N+R-1,7)=1 THEN
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
END IF
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
IF Y>=2016 THEN
IF Y<>2020 AND Y<>2021 AND M=8 AND N=11 THEN
LET DAYCOLOR$="RED"
LET Z$="山の日"
END IF
IF Y<>2020 AND Y<>2021 AND M=8 AND N=12 AND MOD(N+R-1,7)=1 THEN
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
IF Y=2021 AND M=8 AND N=8 THEN
LET DAYCOLOR$="RED"
LET Z$="山の日"
END IF
IF Y=2021 AND M=8 AND N=9 AND MOD(N+R-1,7)=1 THEN
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
IF Y=2020 AND M=8 AND N=10 THEN
LET DAYCOLOR$="RED"
LET Z$="山の日"
END IF
IF Y=2020 AND M=8 AND N=11 AND MOD(N+R-1,7)=1 THEN
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
END IF
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
IF Y>=2003 THEN
IF M=9 AND ((R<=1 AND R+N=16) OR (R>1 AND R+N=23)) THEN
LET DAYCOLOR$="RED"
LET Z$="敬老の日"
END IF
ELSEIF Y>=1966 AND Y<2003 THEN
IF M=9 AND N=15 THEN
LET DAYCOLOR$="RED"
LET Z$="敬老の日"
END IF
IF Y>=1973 AND M=9 AND N=16 AND MOD(N+R-1,7)=1 THEN
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
END IF
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
IF Y=2019 AND M=10 AND N=22 THEN ! 令和元年即位礼正殿の儀は2019年10月22日に執り行われる。
LET DAYCOLOR$="RED"
LET Z$="即位礼正殿の儀"
END IF
IF Y=2019 AND M=10 AND N=23 AND MOD(N+R-1,7)=1 THEN ! 2019年10月23日が月曜なら振替休日とする。
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
IF Y>=2022 THEN
IF M=10 AND ((R<=1 AND R+N=9) OR (R>1 AND R+N=16)) THEN
LET DAYCOLOR$="RED"
LET Z$="体育の日"
END IF
END IF
IF Y=2021 THEN
IF M=7 AND N=23 THEN
LET DAYCOLOR$="RED"
LET Z$="スポーツの日"
END IF
IF M=7 AND N=24 AND MOD(N+R-1,7)=1 THEN
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
END IF
IF Y=2020 THEN
IF M=7 AND N=24 THEN
LET DAYCOLOR$="RED"
LET Z$="スポーツの日"
END IF
IF M=7 AND N=25 AND MOD(N+R-1,7)=1 THEN
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
END IF
IF Y>=2000 AND Y<2020 THEN
IF M=10 AND ((R<=1 AND R+N=9) OR (R>1 AND R+N=16)) THEN
LET DAYCOLOR$="RED"
LET Z$="体育の日"
END IF
ELSEIF Y>=1966 AND Y<2000 THEN
IF M=10 AND N=10 THEN
LET DAYCOLOR$="RED"
LET Z$="体育の日"
END IF
IF Y>=1973 AND M=10 AND N=11 AND MOD(N+R-1,7)=1 THEN
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
END IF
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
IF M=11 AND N=3 THEN
LET DAYCOLOR$="RED"
LET Z$="文化の日"
END IF
IF M=11 AND N=23 THEN
LET DAYCOLOR$="RED"
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
LET Z$="勤労感謝の日"
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
END IF
IF Y>=1973 AND M=11 AND (N=4 OR N=24) AND MOD(N+R-1,7)=1 THEN
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
IF Y=2019 THEN
IF M=12 AND N=23 THEN
LET DAYCOLOR$="BLACK" ! 祝日にならない模様。∴LET DAYCOLOR$="BLACK"
LET Z$="平成の天皇誕生日"
END IF
END IF
IF Y>=1989 AND Y<=2018 THEN
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
IF M=12 AND N=23 THEN
LET DAYCOLOR$="RED"
LET Z$="天皇誕生日"
END IF
IF M=12 AND N=24 AND MOD(N+R-1,7)=1 THEN
LET DAYCOLOR$="RED"
LET Z$="振替休日"
END IF
END IF
LET D$=DATE$
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
! IF Y=VAL(D$(1:4)) AND M=VAL(D$(5:6)) AND N=VAL(D$(7:8)) THEN LET DAYCOLOR$="CYAN" ! ← 当日の日付の色がシアンになる。
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
END FUNCTION
EXTERNAL FUNCTION QSEI$(TM)
DIM A$(9)
MAT READ A$
LET QSEI$=A$(MOD(TM-1,9)+1)
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
!' DATA 九紫火星
!' DATA 八白土星
!' DATA 七赤金星
!' DATA 六白金星
!' DATA 五黄土星
!' DATA 四緑木星
!' DATA 三碧木星
!' DATA 二黒土星
!' DATA 一白水星
DATA " "
DATA " "
DATA " "
DATA " "
DATA " "
DATA " "
DATA " "
DATA " "
DATA " "
END FUNCTION
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
EXTERNAL FUNCTION CALC_ETO60$(ALLYEAR)
DIM A$(10),B$(12)
MAT READ A$,B$
LET CALC_ETO60$=A$(MOD(ALLYEAR+6,10)+1)&B$(MOD(ALLYEAR+8,12)+1)
DATA "甲", "乙", "丙", "丁", "戊"
DATA "己", "庚", "辛", "壬", "癸"
DATA "子", "丑", "寅", "卯", "辰", "巳"
DATA "午", "未", "申", "酉", "戌", "亥"
END FUNCTION
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
EXTERNAL FUNCTION CALC_ETO61$(JOUYOKEI)
DIM A$(60)
MAT READ A$
LET CALC_ETO61$=A$(JOUYOKEI+1)
DATA "甲子","乙丑","丙寅","丁卯","戊辰","己巳","庚午","辛未","壬申","癸酉","甲戌","乙亥","丙子","丁丑","戊寅","己卯","庚辰","辛巳","壬午","癸未"
DATA "甲申","乙酉","丙戌","丁亥","戊子","己丑","庚寅","辛卯","壬辰","癸巳","甲午","乙未","丙申","丁酉","戊戌","己亥","庚子","辛丑","壬寅","癸卯"
DATA "甲辰","乙巳","丙午","丁未","戊申","己酉","庚戌","辛亥","壬子","癸丑","甲寅","乙卯","丙辰","丁巳","戊午","己未","庚申","辛酉","壬戌","癸亥"
END FUNCTION
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
Re: 月齢カレンダーの修正 - gnuutera2012or文句うさびょん URL
2024/03/08 (Fri) 08:38:20
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
!' (1)黄道に沿って、天球を28に区分し、星宿(星座の意)の所在を明瞭にしたもの。太陰(月(つき))はおよそ1日に1宿ず
!' つ運行する。中国では蒼竜(東)・玄武(北)・白虎(西)・朱雀(南)の4宮に分け、さらに各宮を七分した。
!' 東は角(すぼし)・亢(あみぼし)・氏(とも)・房(そい)・心(なかご)・尾(あしたれ)・箕(み)
!' 北は斗(ひきつ)・牛(いなみ)・女(うるき)・虚(とみて)・危(うみやめ)・室(はつい)・壁(なまめ)
!' 西は奎(とかき)・婁(たたら)・胃(えきえ)・昴(すばる)・畢(あめふり)・觜(とろき)・參(からすき)
!' 南は井(ちちり)・鬼(たまほめ)・柳(ぬりこ)・星(ほとほり)・張(ちりこ)・翼(たすき)・軫(みつかけ)
!' (2)(1)のうち、牛宿を除いた二十七宿を月日にあてて吉凶を占う法。宿曜道の系統の選日。【広辞苑】
!' (注)氏(とも)と記載したものは、正しくは、五胡十六国時代の「てい」に該当し、低から人偏をとりさったものと同じである。以下同じ。
!' 二十八宿
EXTERNAL FUNCTION SHUKU28$(JOUYOKEI)
DIM A$(28)
MAT READ A$
LET SHUKU28$=A$(JOUYOKEI+1)
DATA "角","亢","氏","房","心","尾","箕","斗","牛","女","虚","危","室","壁"
DATA "奎","婁","胃","昴","畢","觜","參","井","鬼","柳","星","張","翼","軫"
END FUNCTION
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
!' 中国秦時代からある暦注で、出土した最古の元光元年暦に書かれている。建(たつ),除(のぞく),満(みつ),平(たいら)
!' ,定(さだん),執(とる),破(やぶる),危(あやぶ),成(なる),納(おさん),開(ひらく),閉(とづ)の12あり、納は古い具注暦
!' では収と書かれている。読みは「仮名暦」の記載である。選日法は立春後の最初の寅、啓蟄後の最初の卯、清明後の最
!' 初の辰、立夏後の最初の巳、芒種後の最初の午、小暑後の最初の未、立秋後の最初の申、白露後の最初の酉、寒露後の
!' 最初の戌、立冬後の最初の亥、大雪後の最初の子、小寒後の最初の丑の日を建として順番に配当する。【日本歴史大辞典】
!' 十二直
EXTERNAL FUNCTION TYOKU12$(JOUYOKEI)
DIM A$(12)
MAT READ A$
LET TYOKU12$=A$(JOUYOKEI+1)
DATA "建","除","満","平","定","執","破","危","成","納","開","閉"
END FUNCTION
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
EXTERNAL SUB MOON(X,Y,R,H,N)
DIM XX(73),YY(73)
SET COLOR "GRAY"
DRAW DISK WITH SCALE(R)*SHIFT(X,Y)
SET AREA COLOR "YELLOW"
IF H>15 THEN LET SW=-1 ELSE LET SW=1
LET RR=2*(N-.5)
IF RR>0 THEN
FOR T=0 TO 360 STEP 5
LET B=R
IF T>=90 AND T<=270 THEN LET B=R*RR
LET I=I+1
LET YY(I)=R*SIN(RAD(T))+Y
LET XX(I)=SW*B*COS(RAD(T))+X
NEXT T
ELSE
FOR T=-90 TO 90 STEP 5
LET I=I+1
LET YY(I)=R*SIN(RAD(T))+Y
LET XX(I)=SW*R*COS(RAD(T))+X
NEXT T
LET B=R*ABS(RR)
FOR T=85 TO -90 STEP -5
LET I=I+1
LET YY(I)=R*SIN(RAD(T))+Y
LET XX(I)=SW*B*COS(RAD(T))+X
NEXT T
END IF
IF RR>-1 THEN MAT PLOT AREA :XX,YY
END SUB
!'これより以下は、「旧暦 for VB」から「旧暦.bas」を(仮称)十進BASICに移植したものです。
!' http://www.vector.co.jp/soft/win95/personal/se243537.html?_ga=1.114790919.1276112294.1407498580
!' 旧暦計算 標準モジュール「旧暦.bas」Version 1.0
!' Arranged for Visual Basic 6.0 or 5.0 & Excel97 VBA & Access97 VBA
!' by Masayuki Kanari (C)2002
!'
!' 原典 「旧暦計算サンプルプログラム」
!' Copyright (C) 1993,1994 by H.Takano
!' http://www.vector.co.jp/soft/dos/personal/se016093.html
!'
!' 原典 旧暦計算 JavaScript(ECMAScript) Library "qreki.js" Version 1.5
!' Arranged for ECMAScript(ECMA-262) by Nagano Yutaka (C)1999-2001
!' http://www.ai.wakwak.com/~y-nagano/Programs/koyomi/
!'
!' この標準モジュールの計算結果は無保証です。
!' この標準モジュールはフリーソフトであり、自由に再利用・改良を行ってかまいませんが、
!' 著作権は原典のjgAWK版を開発された高野英明氏、およびJavaScript版を開発された長野隆氏に
!' 帰属しています。上記のリンクより高野氏の「QRSAMP」、長野氏の「qreki.js」を取得し、
!' そのドキュメント内に書かれている再配布規定に従ってください。
!'
!' 使用法
!' 1.旧暦は下記コードをFormモジュールで実行すると、Kyurekiに旧暦が入っています。
!' Kyureki.QYear に旧暦年 Kyureki.QMonth に旧暦月 下記コードの Type Q_Rekiを参照
!' Calc_Kyureki "2002","5","26" "2002"などは当然ですが、変数でも可
!'
!' 2.二十四節季は下記コードをFormモジュールで実行すると、Sekki24に二十四節季が入っています。
!' Sekki24(i,0) に節季の日時 Sekki24(i,1) に節季の名称が入ります。
!' Calc_Sekki24 "2002" "2002"は当然ですが、変数でも可
!'Type Q_Reki ' ユーザー定義型を作成
!' QYear As Integer ' 旧暦年
!' QUruu As Boolean ' 平月:False 閏月:True
!' QMonth As Integer ' 旧暦月
!' QDay As Integer ' 旧暦日
!' QRokuyou As String ' 六曜名
!' QJukkan As String ' 十干十二支
!' QMage ' リアルタイム月齢
!' QMagenoon ' 正午月齢
!' QIllumi ' 輝面比 %
!' QMphase As Integer ' 月相 0~27
!'End Type
!' 十干十二支
EXTERNAL FUNCTION CALC_JUKKAN$(TM)
DIM A$(10),B$(12)
MAT READ A$,B$
LET N$ = A$(MOD(INT(TM / 2), 5) * 2 + MOD(TM ,2) + 1)
DATA "甲", "乙", "丙", "丁", "戊"
DATA "己", "庚", "辛", "壬", "癸"
LET CALC_JUKKAN$ = N$ & " " & B$(MOD(TM - 10,12) + 1)
DATA "子", "丑", "寅", "卯", "辰", "巳"
DATA "午", "未", "申", "酉", "戌", "亥"
END FUNCTION
!' ▼▼▼▼▼▼▼▼▼▼ここから▼▼▼▼▼▼▼▼▼▼
EXTERNAL FUNCTION MEMO_JUKKAN$(TM)
DIM A$(10),B$(12)
MAT READ A$,B$
LET N$ = A$(MOD(INT(TM / 2), 5) * 2 + MOD(TM ,2) + 1)
DATA "甲", "乙", "丙", "丁", "戊"
DATA "己", "庚", "辛", "壬", "癸"
LET MEMO_JUKKAN$ = N$ & "" & B$(MOD(TM - 10,12) + 1)
DATA "子", "丑", "寅", "卯", "辰", "巳"
DATA "午", "未", "申", "酉", "戌", "亥"
END FUNCTION
!' ▲▲▲▲▲▲▲▲▲▲ここまで▲▲▲▲▲▲▲▲▲▲
!' 二分二至の時刻または中気の時刻を求める二分二至の時刻
!' 引数 tm .... 計算対象となる時刻(ユリウス日)
!' logitudeas .... 二分二至の時90 中気の時30
!' 戻り値 .... 二分二至の時刻または中気の時刻(ユリウス日)
!' グローバル変数rm_sun0にその時の太陽黄経をセットする
EXTERNAL FUNCTION CALC_CHU(TM, LOGITUDEAS)
LET TM1 = INT(TM) !' 時刻引数を分解する
LET TM2 = TM - TM1 - 9 / 24 !' JST ==> DT
!' 二分二至の時刻または中気の黄経λsun0を求める
LET T = (TM2 + 0.5 + TM1 - 2451545) / 36525
LET RM_SUN = LONGITUDE_SUN(T)
LET RM_SUN0 = LOGITUDEAS * INT(RM_SUN / LOGITUDEAS)
!' 繰り返し計算によって中気の時刻を計算する(誤差が±1.0 sec以内になったら打ち切る)
DO
LET T = (TM2 + 0.5 + TM1 - 2451545) / 36525
LET RM_SUN = LONGITUDE_SUN(T) !' 太陽の黄経λsunを計算
LET DELTA_RM = RM_SUN - RM_SUN0 !' 黄経差Δλ
!' Δλの引き込み範囲(±180°)を逸脱した場合には、補正を行う
IF DELTA_RM > 180 THEN
LET DELTA_RM = DELTA_RM - 360
ELSEIF DELTA_RM < -180 THEN
LET DELTA_RM = DELTA_RM + 360
END IF
LET DELTA_T1 = INT(DELTA_RM * 365.24219878 / 360) !' 時刻引数の補正値 Δt
LET DELTA_T2 = DELTA_RM * 365.24219878 / 360
LET DELTA_T2 = DELTA_T2 - DELTA_T1
LET TM1 = TM1 - DELTA_T1 !' 時刻引数の補正
LET TM2 = TM2 - DELTA_T2
IF TM2 < 0 THEN
LET TM2 = TM2 + 1
LET TM1 = TM1 - 1
END IF
LOOP UNTIL ABS(DELTA_T1 + DELTA_T2) < (1 / 86400)
LET CALC_CHU = TM1 + TM2 + 9 / 24
END FUNCTION
!' 朔の計算
!' 与えられた時刻の直近の朔の時刻(JST)を求める
!' 引数 tm ........ 計算対象となる時刻(ユリウス日)
!' 戻り値 ........ 朔の時刻 引数、戻り値ともユリウス日で表し、時分秒は日の小数で表す
EXTERNAL FUNCTION CALC_SAKU(TM)
LET LC = 1 !' ループカウンタのセット
LET TM1 = INT(TM) !' 時刻引数を分解する
LET TM2 = TM - TM1 - 9 / 24 !' JST ==> DT
!' 繰り返し計算によって朔の時刻を計算する(誤差が±1.0 sec以内になったら打ち切る)
DO
LET T = (TM2 + 0.5 + TM1 - 2451545) / 36525
LET RM_SUN = LONGITUDE_SUN(T) !' 太陽の黄経λsunを計算
LET RM_MOON = LONGITUDE_MOON(T) !' 月の黄経λmoonを計算
LET DELTA_RM = RM_MOON - RM_SUN !' 月と太陽の黄経差Δλ
!' ループの1回目(Lc=1)で delta_rm < 0 の場合には引き込み範囲に入るように補正する
IF LC = 1 AND DELTA_RM < 0 THEN
LET DELTA_RM = NORMALIZATION_ANGLE(DELTA_RM)
!' 春分の近くで朔がある場合(0 ≦λsun≦ 20)で、月の黄経λmoon≧300 の
!' 場合には、Δλ= 360 - Δλ と計算して補正する
ELSEIF RM_SUN >= 0 AND RM_SUN <= 20 AND RM_MOON >= 300 THEN
LET DELTA_RM = NORMALIZATION_ANGLE(DELTA_RM)
LET DELTA_RM = 360 - DELTA_RM
!' Δλの引き込み範囲(±40°)を逸脱した場合には、補正を行う
ELSEIF ABS(DELTA_RM) > 40 THEN
LET DELTA_RM = NORMALIZATION_ANGLE(DELTA_RM)
END IF
LET DELTA_T1 = INT(DELTA_RM * 29.530589 / 360) !' 時刻引数の補正値 Δt
LET DELTA_T2 = DELTA_RM * 29.530589 / 360
LET DELTA_T2 = DELTA_T2 - DELTA_T1
LET TM1 = TM1 - DELTA_T1 !' 時刻引数の補正
LET TM2 = TM2 - DELTA_T2
IF TM2 < 0 THEN
LET TM2 = TM2 + 1
LET TM1 = TM1 - 1
END IF
!' ループ回数が15回になったら、初期値 tm を tm-26 とする
IF LC = 15 AND ABS(DELTA_T1 + DELTA_T2) > (1 / 86400) THEN
LET TM1 = INT(TM - 26)
LET TM2 = 0
!' 初期値を補正したにも関わらず、振動を続ける場合には初期値を答えとして返して強制的にループを抜け出して異常終了させる
ELSEIF LC > 30 AND ABS(DELTA_T1 + DELTA_T2) > (1 / 86400) THEN
LET TM1 = TM
LET TM2 = 0
EXIT DO
END IF
LET LC = LC + 1
LOOP UNTIL ABS(DELTA_T1 + DELTA_T2) < (1 / 86400)
!' 時刻引数を合成するのと、DT ==> JST 変換を行い、戻り値とする
LET CALC_SAKU = TM2 + TM1 + 9 / 24
END FUNCTION
REM 続き
!' 角度の正規化を行う。すなわち引数の範囲を0≦θ<360にする
EXTERNAL FUNCTION NORMALIZATION_ANGLE(ANGLE)
LET NORMALIZATION_ANGLE = MOD(ANGLE+360,360)
END FUNCTION
EXTERNAL FUNCTION LONGITUDE_SUN(T) !' 太陽の黄経λsunを計算する
!' 摂動項の計算
LET ANG = NORMALIZATION_ANGLE(31557 * T + 161)
LET TH = 0.0004 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(29930 * T + 48)
LET TH = TH + 0.0004 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(2281 * T + 221)
LET TH = TH + 0.0005 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(155 * T + 118)
LET TH = TH + 0.0005 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(33718 * T + 316)
LET TH = TH + 0.0006 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(9038 * T + 64)
LET TH = TH + 0.0007 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(3035 * T + 110)
LET TH = TH + 0.0007 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(65929 * T + 45)
LET TH = TH + 0.0007 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(22519 * T + 352)
LET TH = TH + 0.0013 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(45038 * T + 254)
LET TH = TH + 0.0015 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(445267 * T + 208)
LET TH = TH + 0.0018 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(19 * T + 159)
LET TH = TH + 0.0018 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(32964 * T + 158)
LET TH = TH + 0.002 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(71998.1 * T + 265.1)
LET TH = TH + 0.02 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(35999.05 * T + 267.52)
LET TH = TH - 0.0048 * T * COS(PI * ANG / 180)
LET TH = TH + 1.9147 * COS(PI * ANG / 180)
!' 比例項の計算
LET ANG = NORMALIZATION_ANGLE(36000.7695 * T)
LET ANG = NORMALIZATION_ANGLE(ANG + 280.4659)
LET LONGITUDE_SUN = NORMALIZATION_ANGLE(TH + ANG)
END FUNCTION
EXTERNAL FUNCTION LONGITUDE_MOON(T) !' 月の黄経λmoonを計算する
!' 摂動項の計算
LET ANG = NORMALIZATION_ANGLE(2322131 * T + 191)
LET TH = 0.0003 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(4067 * T + 70)
LET TH = TH + 0.0003 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(549197 * T + 220)
LET TH = TH + 0.0003 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(1808933 * T + 58)
LET TH = TH + 0.0003 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(349472 * T + 337)
LET TH = TH + 0.0003 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(381404 * T + 354)
LET TH = TH + 0.0003 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(958465 * T + 340)
LET TH = TH + 0.0003 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(12006 * T + 187)
LET TH = TH + 0.0004 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(39871 * T + 223)
LET TH = TH + 0.0004 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(509131 * T + 242)
LET TH = TH + 0.0005 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(1745069 * T + 24)
LET TH = TH + 0.0005 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(1908795 * T + 90)
LET TH = TH + 0.0005 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(2258267 * T + 156)
LET TH = TH + 0.0006 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(111869 * T + 38)
LET TH = TH + 0.0006 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(27864 * T + 127)
LET TH = TH + 0.0007 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(485333 * T + 186)
LET TH = TH + 0.0007 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(405201 * T + 50)
LET TH = TH + 0.0007 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(790672 * T + 114)
LET TH = TH + 0.0007 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(1403732 * T + 98)
LET TH = TH + 0.0008 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(858602 * T + 129)
LET TH = TH + 0.0009 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(1920802 * T + 186)
LET TH = TH + 0.0011 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(1267871 * T + 249)
LET TH = TH + 0.0012 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(1856938 * T + 152)
LET TH = TH + 0.0016 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(401329 * T + 274)
LET TH = TH + 0.0018 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(341337 * T + 16)
LET TH = TH + 0.0021 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(71998 * T + 85)
LET TH = TH + 0.0021 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(990397 * T + 357)
LET TH = TH + 0.0021 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(818536 * T + 151)
LET TH = TH + 0.0022 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(922466 * T + 163)
LET TH = TH + 0.0023 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(99863 * T + 122)
LET TH = TH + 0.0024 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(1379739 * T + 17)
LET TH = TH + 0.0026 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(918399 * T + 182)
LET TH = TH + 0.0027 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(1934 * T + 145)
LET TH = TH + 0.0028 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(541062 * T + 259)
LET TH = TH + 0.0037 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(1781068 * T + 21)
LET TH = TH + 0.0038 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(133 * T + 29)
LET TH = TH + 0.004 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(1844932 * T + 56)
LET TH = TH + 0.004 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(1331734 * T + 283)
LET TH = TH + 0.004 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(481266 * T + 205)
LET TH = TH + 0.005 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(31932 * T + 107)
LET TH = TH + 0.0052 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(926533 * T + 323)
LET TH = TH + 0.0068 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(449334 * T + 188)
LET TH = TH + 0.0079 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(826671 * T + 111)
LET TH = TH + 0.0085 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(1431597 * T + 315)
LET TH = TH + 0.01 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(1303870 * T + 246)
LET TH = TH + 0.0107 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(489205 * T + 142)
LET TH = TH + 0.011 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(1443603 * T + 52)
LET TH = TH + 0.0125 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(75870 * T + 41)
LET TH = TH + 0.0154 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(513197.9 * T + 222.5)
LET TH = TH + 0.0304 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(445267.1 * T + 27.9)
LET TH = TH + 0.0347 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(441199.8 * T + 47.4)
LET TH = TH + 0.0409 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(854535.2 * T + 148.2)
LET TH = TH + 0.0458 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(1367733.1 * T + 280.7)
LET TH = TH + 0.0533 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(377336.3 * T + 13.2)
LET TH = TH + 0.0571 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(63863.5 * T + 124.2)
LET TH = TH + 0.0588 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(966404 * T + 276.5)
LET TH = TH + 0.1144 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(35999.05 * T + 87.53)
LET TH = TH + 0.1851 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(954397.74 * T + 179.93)
LET TH = TH + 0.2136 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(890534.22 * T + 145.7)
LET TH = TH + 0.6583 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(413335.35 * T + 10.74)
LET TH = TH + 1.274 * COS(PI * ANG / 180)
LET ANG = NORMALIZATION_ANGLE(477198.868 * T + 44.963)
LET TH = TH + 6.2888 * COS(PI * ANG / 180)
!' 比例項の計算
LET ANG = NORMALIZATION_ANGLE(481267.8809 * T)
LET ANG = NORMALIZATION_ANGLE(ANG + 218.3162)
LET LONGITUDE_MOON = NORMALIZATION_ANGLE(TH + ANG)
END FUNCTION
!' ユリウス日(JD)から年月日、時分秒(世界時)を計算する
!' この関数で求めた年月日は、グレゴリオ暦法によって表されている
EXTERNAL FUNCTION JD2YMDT$(JD)
LET X0 = INT(JD + 68570)
LET X1 = INT(X0 / 36524.25)
LET X2 = X0 - INT(36524.25 * X1 + 0.75)
LET X3 = INT((X2 + 1) / 365.2425)
LET X4 = X2 - INT(365.25 * X3) + 31
LET X5 = INT(INT(X4) / 30.59)
LET X6 = INT(INT(X5) / 11)
LET GDAY = X4 - INT(30.59 * X5)
LET GMONTH = X5 - 12 * X6 + 2
LET GYEAR = 100 * (X1 - 49) + X3 + X6
!' 2月30日の補正
IF GMONTH = 2 AND GDAY > 28 THEN
IF MOD(GYEAR,100) = 0 AND MOD(GYEAR,400) = 0 THEN
LET GDAY = 29
ELSEIF MOD(GYEAR,4) = 0 AND MOD(GYEAR,100) > 0 THEN
LET GDAY = 29
ELSE
LET GDAY = 28
END IF
END IF
LET X0 = 24 * (JD - INT(JD))
LET GHOUR = INT(X0)
LET GMINUTE = INT((X0 - GHOUR) * 60)
LET GSECOND = INT((X0 - GHOUR - GMINUTE / 60) * 3600 + 0.05)
LET JD2YMDT$ = STR$(GYEAR) & "/" & RIGHT$("0"&STR$(GMONTH),2) & "/" & RIGHT$("0"&STR$(GDAY),2) & " " & RIGHT$("0"&STR$(GHOUR),2) & ":" & RIGHT$("0"&STR$(GMINUTE),2) & ":" & RIGHT$("0"&STR$(GSECOND),2)
END FUNCTION
!' 年月日、時分秒(世界時)からユリウス日(JD)を計算する
EXTERNAL FUNCTION YMDT2JD(GYEAR, GMONTH, GDAY, GHOUR, GMINUTE, GSECOND)
IF GMONTH < 3 THEN
LET CALC_GYEAR = GYEAR - 1
LET CALC_GMONTH = GMONTH + 12
ELSE
LET CALC_GYEAR = GYEAR
LET CALC_GMONTH = GMONTH
END IF
LET Y = INT(365.25 * CALC_GYEAR) + INT(CALC_GYEAR / 400) - INT(CALC_GYEAR / 100)
LET Y = Y + INT(30.59 * (CALC_GMONTH - 2)) + 1721088 + GDAY
LET YMDT2JD = Y + (GHOUR + GMINUTE / 60 + GSECOND / 3600) / 24
END FUNCTION
!' 二十四節季
!' Sekki(x,0) .... 節季日
!' Sekki(x,1) .... 節季
EXTERNAL SUB CALC_SEKKI24(GYEAR)
DIM A$(24)
MAT READ A$
LET YMD = YMDT2JD(GYEAR, 1, 1, 0, 0, 0)
LET J = 0
FOR I = 0 TO 400 STEP 15
LET SEKKI$ = JD2YMDT$(CALC_CHU(YMD + I, 15))
IF VAL(LEFT$(SEKKI$, 4)) = GYEAR THEN
LET SEKKI24$(J, 0) = SEKKI$
LET SEKKI24$(J, 1) = A$(RM_SUN0 / 15+1)
DATA "春分", "清明", "穀雨", "立夏", "小満", "芒種"
DATA "夏至", "小暑", "大暑", "立秋", "処暑", "白露"
DATA "秋分", "寒露", "霜降", "立冬", "小雪", "大雪"
DATA "冬至", "小寒", "大寒", "立春", "雨水", "啓蟄"
LET J = J + 1
END IF
NEXT I
END SUB
!' 新暦に対応する、旧暦を求める
!' 引数 tm .... 計算する日付(ユリウス日)
!' 戻り値 .... kyureki
EXTERNAL SUB CALC_KYUREKI(GYEAR, GMONTH, GDAY)
DIM CHU(0 TO 4), SAKU(0 TO 5), M(0 TO 5, 0 TO 2),ROKU$(6)
LET TM = YMDT2JD(GYEAR, GMONTH, GDAY, 0, 0, 0)
LET CHU(0) = CALC_CHU(TM, 90) !' 計算対象の直前にあたる二分二至の時刻を求める
LET M(0, 0) = INT(RM_SUN0 / 30) + 2 !' 上で求めた二分二至の時の太陽黄経をもとに朔日行列の先頭に月名をセット
FOR I = 1 TO 4
LET CHU(I) = CALC_CHU(CHU(I - 1) + 32, 30)
NEXT I
!' 計算対象の直前にあたる二分二至の直前の朔の時刻を求める
LET SAKU(0) = CALC_SAKU(CHU(0))
!' 朔の時刻を求める
FOR I = 1 TO 5
LET SAKU(I) = CALC_SAKU(SAKU(I - 1) + 30)
!' 前と同じ時刻を計算した場合(両者の差が26日以内)には、初期値を+33日にして再実行させる
IF ABS(INT(SAKU(I - 1)) - INT(SAKU(I))) <= 26 THEN
LET SAKU(I) = CALC_SAKU(SAKU(I - 1) + 35)
END IF
NEXT I
!' saku(1)が二分二至の時刻以前になってしまった場合には、朔をさかのぼり過ぎたと考えて、
!' 朔の時刻を繰り下げて修正する
!' その際、計算もれsaku(4)になっている部分を補うため、朔の時刻を計算する
!' 近日点通過の近辺で朔があると起こる事があるようだ...?
IF INT(SAKU(1)) <= INT(CHU(0)) THEN
FOR I = 0 TO 4
LET SAKU(I) = SAKU(I + 1)
NEXT I
LET SAKU(4) = CALC_SAKU(SAKU(3) + 35)
!' saku(0)が二分二至の時刻以後になってしまった場合には、朔をさかのぼり足りないと見て、
!' 朔の時刻を繰り上げて修正する
!' その際、計算もれsaku(0)になっている部分を補うため、朔の時刻を計算する
!' 春分点の近辺で朔があると起こる事があるようだ...?
ELSEIF INT(SAKU(0)) > INT(CHU(0)) THEN
FOR I = 4 TO 1 STEP -1
LET SAKU(I) = SAKU(I - 1)
NEXT I
LET SAKU(0) = CALC_SAKU(SAKU(0) - 27)
END IF
!' 閏月検索Flagセット 節月で4ヶ月の間に朔が5回あると、閏月がある可能性がある
!' lap=false:平月 lap=true:閏月
IF INT(SAKU(4)) <= INT(CHU(3)) THEN LET LAP=1 ELSE LET LAP=0
!' 朔日行列の作成
!' m(i,0) ... 月名(1:正月 2:2月 3:3月 ....)
!' m(i,1) ... 閏フラグ(false:平月 true:閏月)
!' m(i,2) ... 朔日のjd
!' m(0, 0)はこの関数の始めの方ですでに代入済み
LET M(0, 1) = 0
LET M(0, 2) = INT(SAKU(0))
FOR I = 1 TO 5
IF LAP=1 AND I > 1 THEN
IF CHU(I - 1) <= INT(SAKU(I - 1)) OR CHU(I - 1) >= INT(SAKU(I)) THEN
LET M(I - 1, 0) = M(I - 2, 0)
LET M(I - 1, 1) = 1
LET M(I - 1, 2) = INT(SAKU(I - 1))
LET LAP = 0
END IF
END IF
LET M(I, 0) = M(I - 1, 0) + 1
IF M(I, 0) > 12 THEN
LET M(I, 0) = M(I, 0) - 12
END IF
LET M(I, 2) = INT(SAKU(I))
LET M(I, 1) = 0
NEXT I
!' 朔日行列から旧暦を求める
LET STATE = 0
FOR I = 0 TO 5
IF INT(TM) < INT(M(I, 2)) THEN
LET STATE = 1
EXIT FOR
ELSEIF INT(TM) = INT(M(I, 2)) THEN
LET STATE = 2
EXIT FOR
END IF
NEXT I
IF STATE = 0 OR STATE = 1 THEN
LET I = I - 1
END IF
LET QURUU = M(I, 1)
LET QMONTH = M(I, 0)
LET QDAY = INT(TM) - INT(M(I, 2)) + 1
!'旧暦年の計算 旧暦月が10以上でかつ新暦月より大きい場合には、まだ年を越していないはず...
!'YMD$ = JD2YMDT$(tm)
!'QYear = Val(Left$(YMD$, 4))
!'If QMonth > 9 And QMonth > Val(Mid$(YMD$, 6, 2)) Then
LET QYEAR = GYEAR
IF QMONTH > 9 AND QMONTH > GMONTH THEN
LET QYEAR = QYEAR - 1
END IF
!' 六曜を求める
MAT READ ROKU$
DATA "大安", "赤口", "先勝", "友引", "先負", "仏滅"
LET QROKUYOU$ = ROKU$(MOD((QMONTH + QDAY) ,6) + 1)
!' 十干十二支を求める
LET QJUKKAN$ = CALC_JUKKAN$(TM)
!' リアルタイム月齢を求める
LET QMAGE = TM - SAKU(I)
IF QMAGE < 0 THEN
LET QMAGE = TM - SAKU(I - 1)
END IF
!' 正午月齢を求める
LET QMAGENOON = INT(TM) + 0.5 - SAKU(I)
IF QMAGENOON < 0 THEN
LET QMAGENOON = INT(TM) + 0.5 - SAKU(I - 1)
END IF
!' 輝面比を求める
LET TM1 = INT(TM)
LET TM2 = TM - TM1 - 9 / 24
LET T = (TM2 + 0.5) / 36525 + (TM1 - 2451545) / 36525
LET QILLUMI = (1 - COS(PI * NORMALIZATION_ANGLE(LONGITUDE_MOON(T) - LONGITUDE_SUN(T)) / 180)) * 50
!' 月相を求める 輝面比の計算で求めた変数tを使用
LET QMPHASE = INT(NORMALIZATION_ANGLE(LONGITUDE_MOON(T) - LONGITUDE_SUN(T)) / 360 * 28 + 0.5)
LET QMPHASE = MOD(QMPHASE, 28)
END SUB
人工知能でプログラミング - しばっち
2024/02/25 (Sun) 08:38:56
copilot(Windows AI)で十進BASICプログラム作ってみた。
https://copilot.microsoft.com/
現状では若干の追記・修正が必要なようです。
AI(人工知能)で大まかに生成してエラー箇所を
修正していけばプログラミングはできる
のではないでしょうか!?
RANDOMIZE
10 PRINT "数あてゲームを始めます!"
20 LET ANSWER = INT(RND * 100) + 1
30 INPUT PROMPT "1から100までの数字を入力してください:": GUESS
40 IF GUESS = ANSWER THEN
PRINT "正解です!"
STOP
END IF
50 IF GUESS < ANSWER THEN
PRINT "もっと大きな数字です。"
GOTO 30
END IF
60 IF GUESS > ANSWER THEN
PRINT "もっと小さな数字です。"
GOTO 30
END IF
END
実行結果
数あてゲームを始めます!
1から100までの数字を入力してください:50
もっと大きな数字です。
1から100までの数字を入力してください:75
もっと大きな数字です。
1から100までの数字を入力してください:87
もっと大きな数字です。
1から100までの数字を入力してください:93
もっと大きな数字です。
1から100までの数字を入力してください:96
もっと大きな数字です。
1から100までの数字を入力してください:99
正解です!
マンデルボックス - しばっち
2024/02/12 (Mon) 08:13:37
マンデルボックス
https://en.wikipedia.org/wiki/Mandelbox
https://digitalfreepen.com/mandelbox370/
https://www.fractalforums.com/programming/mandelbox-2d-questions-and-code-attempt/
とりあえずそれっぽいものは描けるようですが、もしプログラム(アルゴリズム)が間違っていても悪しからず。
マンデルボックスでは複素数ではなく、ベクトルで特定の計算をします。
SCALEやITERを変更するとパターンが変わります。
PUBLIC NUMERIC Z(2),C(2),SCALE
FOR I=0 TO 7
SET COLOR MIX(I) BITAND(I,2)/2,BITAND(I,4)/4,BITAND(I,1)
NEXT I
CLEAR
SET POINT STYLE 1
LET SCALE=2
LET ITER=6
SET WINDOW -1,1,1,-1
ASK BITMAP SIZE XSIZE,YSIZE
FOR Y=0 TO YSIZE
FOR X=0 TO XSIZE
MAT Z=ZER
LET C(1)=WORLDX(X)
LET C(2)=WORLDY(Y)
FOR K=1 TO ITER
CALL ITERATE(Z)
NEXT K
SET POINT COLOR MAGNITUDE(Z)+1
PLOT POINTS:WORLDX(X),WORLDY(Y)
NEXT X
NEXT Y
END
EXTERNAL SUB ITERATE(Z())
FOR I=1 TO 2
IF Z(I)>1 THEN
LET Z(I)=2-Z(I)
ELSEIF Z(I)<-1 THEN
LET Z(I)=-2-Z(I)
END IF
NEXT I
IF MAGNITUDE(Z)<.5 THEN
MAT Z=4*Z
ELSEIF MAGNITUDE(Z)<1 THEN
MAT Z=(1/MAGNITUDE(Z)^2)*Z
END IF
MAT Z=SCALE*Z
MAT Z=Z+C
END SUB
EXTERNAL FUNCTION MAGNITUDE(Z())
LET MAGNITUDE=SQR(DOT(Z,Z))
END FUNCTION
----------------------------------------------------------------------------------------
DIM Z(2),C(2)
FOR I=0 TO 255
SET COLOR MIX(I) I/255,I/255,I/255
NEXT I
CLEAR
LET SCALE=-2.5
LET ITER=50
SET WINDOW -2,2,2,-2
ASK BITMAP SIZE XSIZE,YSIZE
DIM MAP(0 TO XSIZE,0 TO YSIZE)
FOR Y=0 TO YSIZE
FOR X=0 TO XSIZE
MAT Z=ZER
LET C(1)=WORLDX(X)
LET C(2)=WORLDY(Y)
FOR K=1 TO ITER
CALL T(SCALE,Z,C)
IF MAGNITUDE(Z)>4 THEN EXIT FOR
NEXT K
IF K>=ITER THEN
LET MAP(X,Y)=0
ELSE
LET MAP(X,Y)=MAGNITUDE(Z)+1
END IF
LET HIGHVAL=MAX(HIGHVAL,MAP(X,Y))
NEXT X
NEXT Y
FOR Y=0 TO YSIZE
FOR X=0 TO XSIZE
LET MAP(X,Y)=MAP(X,Y)*255/HIGHVAL
NEXT X
NEXT Y
MAT PLOT CELLS ,IN -2,-2;2,2:MAP
END
EXTERNAL SUB T(SCALE,Z(),C())
CALL FBOX(Z)
CALL FBALL(Z)
MAT Z=SCALE*Z
MAT Z=Z+C
END SUB
EXTERNAL SUB FBOX(Z())
FOR I=1 TO 2
IF Z(I)>1 THEN
LET Z(I)=2-Z(I)
ELSEIF Z(I)<-1 THEN
LET Z(I)=-2-Z(I)
END IF
NEXT I
END SUB
EXTERNAL SUB FBALL(Z())
IF MAGNITUDE(Z)<.5 THEN
MAT Z=4*Z
ELSEIF MAGNITUDE(Z)<1 THEN
MAT Z=(1/MAGNITUDE(Z)^2)*Z
END IF
END SUB
EXTERNAL FUNCTION MAGNITUDE(Z())
LET MAGNITUDE=SQR(DOT(Z,Z))
END FUNCTION
----------------------------------------------------------------------------------------
PUBLIC NUMERIC Z(2),C(2),SCALE
FOR I=0 TO 7
SET COLOR MIX(I) BITAND(I,2)/2,BITAND(I,4)/4,BITAND(I,1)
NEXT I
CLEAR
SET POINT STYLE 1
LET SCALE=1.5
LET ITER=100
LET S=2
SET WINDOW -S,S,S,-S
ASK BITMAP SIZE XSIZE,YSIZE
FOR Y=0 TO YSIZE
FOR X=0 TO XSIZE
MAT Z=ZER
LET C(1)=WORLDX(X)
LET C(2)=WORLDY(Y)
FOR K=1 TO ITER
CALL ITERATE(Z)
IF MAGNITUDE(Z)>4 THEN
SET POINT COLOR MAGNITUDE(Z)+1
PLOT POINTS:WORLDX(X),WORLDY(Y)
EXIT FOR
END IF
NEXT K
NEXT X
NEXT Y
END
EXTERNAL SUB ITERATE(Z())
FOR I=1 TO 2
IF Z(I)>1 THEN
LET Z(I)=2-Z(I)
ELSEIF Z(I)<-1 THEN
LET Z(I)=-2-Z(I)
END IF
NEXT I
IF MAGNITUDE(Z)<.5 THEN
MAT Z=4*Z
ELSEIF MAGNITUDE(Z)<1 THEN
MAT Z=(1/MAGNITUDE(Z)^2)*Z
END IF
MAT Z=SCALE*Z
MAT Z=Z+C
END SUB
EXTERNAL FUNCTION MAGNITUDE(Z())
LET MAGNITUDE=SQR(DOT(Z,Z))
END FUNCTION