
Windowsで音を出力する - SHIRAISHI Kazuo
2026/07/30 (Thu) 16:24:42
https://decimalbasic.web.fc2.com/QA-WAV.htm(WAVファイルを作成する・読む)
の手法で音を作成することができますが,Windows APIを利用してファイルを介さずに音が出せるはずなので試しました。
次に示すのは32ビット版です。Ver.7,Ver.8とBASICAccで動作します。
1秒当たり44100個の波形データを配列に用意し,WaveOutを実行します。
波形データの数値は-1以上,1以下でなければなりません。
音を変えたいとき変更が必要なのは,1050~1120行の部分です。
波形データのうち,最初の1000個(約22.7ミリ秒分)をグラフで表示します。絶対値が1を超えないように管理してください。
倍音の位相を変えると波形が変わるのに,人の耳には同じ音に聞こえることなどが確かめられます。
1000 OPTION ARITHMETIC native
1010 OPTION CHARACTER BYTE
1020 DECLARE EXTERNAL SUB SoundMono.Waveout
1030 DECLARE EXTERNAL NUMERIC SoundMono.SAMPLE_RATE
1040 DECLARE NUMERIC wlen
1050 LET wlen=SAMPLE_RATE * 1.5 ! SAMPLE_RATE × 秒数
1060 DIM w(wlen)
1070 DECLARE NUMERIC i,t,f
1080 LET f=175 ! 基音(Hz)
1090 FOR i=1 TO wlen
1100 LET t=i/SAMPLE_RATE
1110 LET w(i)=0.5*SIN(2*PI*f*t) + 0.1*SIN(2*PI*2*f*t) + 0.3*SIN(2*PI*3*f*t) + 0.1*SIN(2*PI*5*f*t)
1120 NEXT i
1130 CALL WaveOut(w)
1140 END
10000 REM 音声波出力 32ビットWindows版
10010 MODULE SoundMono
10020 MODULE OPTION ARITHMETIC native
10030 MODULE OPTION CHARACTER byte
10035 PUBLIC SUB WaveOut
10040 SHARE SUB DeviceOpen
10050 SHARE SUB DeviceClose
10060 SHARE SUB WaveOut0
10070 PUBLIC NUMERIC SAMPLE_RATE
10080 LET SAMPLE_RATE = 44100 ! サンプリング周波数 (44.1kHz)
10090 SHARE NUMERIC BufferLength
10100 SHARE NUMERIC hWaveOut ! Audio device ハンドル
10110 SHARE STRING Buffer1$
10120 SHARE STRING header1$
10130 SHARE NUMERIC SizeOfWAVEHDR
10140 LET SizeOfWAVEHDR=4*8 ! 64bit Windowsでは要修正
10150 EXTERNAL SUB WaveOut(w())
10160 SET WINDOW 0,1000,-2,2
10170 DRAW grid(10,1) WITH SCALE(SAMPLE_RATE/1000,1)
10180 DECLARE NUMERIC i
10190 FOR i=1 TO 1000
10200 PLOT POINTS:i,w(i)
10210 NEXT i
10220 DECLARE NUMERIC wlen
10230 LET wlen=UBOUND(w)
10240 CALL DeviceOpen(wlen)
10250 CALL WaveOut0(w)
10260 CALL DeviceClose
10270 END SUB
10280 EXTERNAL SUB DeviceOpen(BufLen)
10290 ! wave format 16bit, モノラル
10300 LET BufferLength=BufLen
10310 DECLARE NUMERIC wFormatTag, nChannels, nSamplesPerSec, wBitsPerSample, nBlockAlign, nAvgBytesPerSec, cbsize
10320 DECLARE STRING wfx$ ! wave format struct tWAVEFORMATEX
10330 LET wFormatTag = 1 ! WAVE_FORMAT_PCM;
10340 LET nChannels = 1 ! モノラル
10350 LET nSamplesPerSec = SAMPLE_RATE
10360 LET wBitsPerSample = 16
10370 LET nBlockAlign = (nChannels * wBitsPerSample) / 8
10380 LET nAvgBytesPerSec = nSamplesPerSec * nBlockAlign
10390 LET cbsize=0
10400 LET wfx$=word$(wFormatTag) & WoRD$(nChannels) & DWORD$(nSamplesPerSec) & DWORD$(nAvgBytesPerSec) & WORD$(nBlockAlign) & WORD$(wBitsPerSample) & WORD$(cbSize)
10410 ! オーディオデバイスのオープン
10420 FUNCTION waveOutOpen(lphWaveOut$, uDeviceID , lpFormat$, ByVal, dwInstance , dwFlags)
10430 assign "winmm.dll" ,"waveOutOpen"
10440 END FUNCTION
10450 DECLARE STRING hWaveOut$
10460 LET hWaveOut$=REPEAT$(CHR$(0),4)
10470 IF waveOutOpen(hWaveOut$, -1, wfx$, 0, 0, 0) <>0 THEN
10480 PRINT "オーディオデバイスを開けませんでした。"
10490 STOP
10500 END IF
10510 DECLARE EXTERNAL FUNCTION VarPtr, DWord
10520 LET hWaveOut=DWord(hWaveOut$,0)
10530 DECLARE NUMERIC header1_lpData, dwBufferLength
10540 !typedef struct wavehdr_tag {
10550 ! LPSTR lpData;
10560 ! DWORD dwBufferLength;
10570 ! DWORD dwBytesRecorded;
10580 ! DWORD_PTR dwUser;
10590 ! DWORD dwFlags;
10600 ! DWORD dwLoops;
10610 ! struct wavehdr_tag *lpNext;
10620 ! DWORD_PTR reserved;
10630 !} WAVEHDR, *PWAVEHDR, *NPWAVEHDR, *LPWAVEHDR;
10640 LET buffer1$=REPEAT$(CHR$(0),2*BufferLength)
10650 LET header1$=REPEAT$(CHR$(0),SizeOfWAVEHDR)
10660 LET header1_lpData = VarPtr(buffer1$)
10670 LET dwBufferLength = BufferLength * 2
10680 LET header1$(1:4)=Dword$(header1_lpData)
10690 LET header1$(5:8)=DWord$(dwBufferLength)
10700 SUB waveOutPrepareHeader( hWaveOut, lpWaveOutHdr$ , uSize )
10710 assign "winmm.dll" , "waveOutPrepareHeader"
10720 END SUB
10730 CALL waveOutPrepareHeader(hWaveOut, header1$, SizeOfWAVEHDR)
10740 END SUB
10750 EXTERNAL SUB DeviceClose
10760 SUB waveOutReset(hWaveOut)
10770 assign "winmm.dll" ,"waveOutReset"
10780 END SUB
10790 SUB waveOutUnprepareHeader( hWaveOut, lpWaveOutHdr$ , uSize )
10800 assign "winmm.dll" , "waveOutUnprepareHeader"
10810 END SUB
10820 SUB waveOutClose(hWaveOut)
10830 assign "winmm.dll" ,"waveOutClose"
10840 END SUB
10850 CALL waveOutReset(hWaveOut)
10860 CALL waveOutUnprepareHeader(hWaveOut, header1$, SizeOfWAVEHDR)
10870 call waveOutClose(hWaveOut)
10880 END SUB
10890 EXTERNAL SUB WaveOut0(w())
10900 SUB waveOutWrite(hWaveOut, header$, SizeOfWAVEHDR)
10910 assign "winmm.dll" ,"waveOutWrite"
10920 END SUB
10930 DECLARE NUMERIC i
10940 FOR i=1 TO BufferLength
10950 LET buffer1$(i*2-1: i*2) = WORD$(32767*w(i))
10960 NEXT i
10970 CALL waveOutWrite(hWaveOut, header1$, SizeOfWAVEHDR)
10980 DECLARE NUMERIC WHDR_DONE
10990 DECLARE EXTERNAL FUNCTION DWord
11000 LET WHDR_DONE=1
11010 DO WHILE BITAND(Dword(header1$,16), WHDR_DONE)=0 !header1$(16:19)はdwFlags
11020 WAIT DELAY 0.01
11030 LOOP
11040 END SUB
11050 END MODULE
11060 EXTERNAL FUNCTION VarPtr(s$)
11070 OPTION ARITHMETIC NATIVE
11080 OPTION CHARACTER byte
11090 FUNCTION CharPrev(s$,t$)
11100 ASSIGN "user32.dll","CharPrevA"
11110 END FUNCTION
11120 LET VarPtr=CharPrev(s$,s$)
11130 END FUNCTION
11140 EXTERNAL FUNCTION DWord(s$,p)
11150 OPTION ARITHMETIC NATIVE
11160 OPTION CHARACTER byte
11170 DECLARE NUMERIC n, i
11180 LET n=0
11190 FOR i=1 TO 4
11200 LET n=n+256^(i-1)*ORD(s$(p+i:p+i))
11210 NEXT i
11220 LET Dword=n
11230 END FUNCTION
Windows APIで音を出すのはかなり面倒です。
まず,waveOutOpen
https://learn.microsoft.com/ja-jp/windows/win32/api/mmeapi/nf-mmeapi-waveoutopen
を実行してオーディオデバイスのハンドルを取得します(10470行)。
次に,waveOutPrepareHeader
https://learn.microsoft.com/ja-jp/windows/win32/api/mmeapi/nf-mmeapi-waveoutprepareheader
を実行して,波形データを置く領域を指定します(10730行)。
実際の波形データ(16ビット)はBuffer1$に置くのですが,それが,Header1$を介して間接的に指定されます。
そして,waveOutWrite
https://learn.microsoft.com/ja-jp/windows/win32/api/mmeapi/nf-mmeapi-waveoutwrite
を実行して音を出します(10970行)。
そして,11010行に示すようにヘッダのdwFlagsのWHDR_DONEビットが1になるのを待ちます(演奏終了)。
Re: Windowsで音を出力する - SHIRAISHI Kazuo
2026/07/30 (Thu) 16:50:19
64ビット版です。Ver.0.9.4.4とBASICAccで動作します。Ver.0.9.4.3では動作しません。
1000 OPTION ARITHMETIC native
1010 OPTION CHARACTER BYTE
1020 DECLARE EXTERNAL SUB SoundMono.Waveout
1030 DECLARE EXTERNAL NUMERIC SoundMono.SAMPLE_RATE
1040 DECLARE NUMERIC wlen
1050 LET wlen=SAMPLE_RATE * 1.5 ! SAMPLE_RATE × 秒数
1060 DIM w(wlen)
1070 DECLARE NUMERIC i,t,f
1080 LET f=175 ! 基音(Hz)
1090 FOR i=1 TO wlen
1100 LET t=i/SAMPLE_RATE
1110 LET w(i)=0.2*SIN(2*PI*f*t) + 0.4*SIN(2*PI*2*f*t) + 0.1*SIN(2*PI*4*f*t) + 0.1*SIN(2*PI*6*f*t)
1120 NEXT i
1130 CALL WaveOut(w)
1140 PRINT "終了"
1150 END
10000 REM 音声波出力 64ビットWindows版
10010 MODULE SoundMono
10020 MODULE OPTION ARITHMETIC native
10030 MODULE OPTION CHARACTER byte
10035 PUBLIC SUB WaveOut
10040 SHARE SUB DeviceOpen
10050 SHARE SUB DeviceClose
10060 SHARE SUB WaveOut0
10070 PUBLIC NUMERIC SAMPLE_RATE
10080 LET SAMPLE_RATE = 44100 ! サンプリング周波数 (44.1kHz)
10090 SHARE NUMERIC BufferLength
10100 SHARE NUMERIC hWaveOut ! Audio device ハンドル
10110 SHARE STRING Buffer1$
10120 SHARE STRING header1$
10130 SHARE NUMERIC SizeOfWAVEHDR
10140 LET SizeOfWAVEHDR = 8+4+4+8+4+4+8+8 ! 64bit Windows
10150 EXTERNAL SUB WaveOut(w())
10160 SET WINDOW 0,1000,-2,2
10170 DRAW grid(10,1) WITH SCALE(SAMPLE_RATE/1000,1)
10180 DECLARE NUMERIC i
10190 FOR i=1 TO 1000
10200 PLOT POINTS:i,w(i)
10210 NEXT i
10220 DECLARE NUMERIC wlen
10230 LET wlen=UBOUND(w)
10240 CALL DeviceOpen(wlen)
10250 CALL WaveOut0(w)
10260 CALL DeviceClose
10270 END SUB
10280 EXTERNAL SUB DeviceOpen(BufLen)
10290 ! wave format 16bit, モノラル
10300 LET BufferLength=BufLen
10310 DECLARE NUMERIC wFormatTag, nChannels, nSamplesPerSec, wBitsPerSample, nBlockAlign, nAvgBytesPerSec, cbsize
10320 DECLARE STRING wfx$ ! wave format struct tWAVEFORMATEX
10330 LET wFormatTag = 1 ! WAVE_FORMAT_PCM;
10340 LET nChannels = 1 ! モノラル
10350 LET nSamplesPerSec = SAMPLE_RATE
10360 LET wBitsPerSample = 16
10370 LET nBlockAlign = (nChannels * wBitsPerSample) / 8
10380 LET nAvgBytesPerSec = nSamplesPerSec * nBlockAlign
10390 LET cbsize=0
10400 LET wfx$=word$(wFormatTag) & WoRD$(nChannels) & DWORD$(nSamplesPerSec) & DWORD$(nAvgBytesPerSec) & WORD$(nBlockAlign) & WORD$(wBitsPerSample) & WORD$(cbSize)
10410 ! オーディオデバイスのオープン
10420 FUNCTION waveOutOpen(lphWaveOut$, uDeviceID , lpFormat$, ByVal, dwInstance , dwFlags)
10430 assign "winmm.dll" ,"waveOutOpen"
10440 END FUNCTION
10450 DECLARE STRING hWaveOut$
10460 DECLARE NUMERIC testval
10470 LET hWaveOut$=REPEAT$(CHR$(0),8)
10480 LET testval =waveOutOpen(hWaveOut$, -1, wfx$, 0, 0, 0)
10490 IF testval<>0 THEN
10500 PRINT testval,"オーディオデバイスを開けませんでした。"
10510 STOP
10520 END IF
10530 DECLARE EXTERNAL FUNCTION VarPtr, QWord, QWord$
10540 LET hWaveOut=QWord(hWaveOut$,0)
10550 DECLARE NUMERIC header1_lpData, dwBufferLength
10560 !typedef struct wavehdr_tag {
10570 ! LPSTR lpData;
10580 ! DWORD dwBufferLength;
10590 ! DWORD dwBytesRecorded;
10600 ! DWORD_PTR dwUser;
10610 ! DWORD dwFlags;
10620 ! DWORD dwLoops;
10630 ! struct wavehdr_tag *lpNext;
10640 ! DWORD_PTR reserved;
10650 !} WAVEHDR, *PWAVEHDR, *NPWAVEHDR, *LPWAVEHDR;
10660 LET buffer1$=REPEAT$(CHR$(0),2*BufferLength)
10670 LET header1$=REPEAT$(CHR$(0),SizeOfWAVEHDR)
10680 LET header1_lpData = VarPtr(buffer1$)
10690 LET dwBufferLength = BufferLength * 2
10700 LET header1$(1:8)=Qword$(header1_lpData)
10710 LET header1$(9:12)=DWord$(dwBufferLength)
10720 SUB waveOutPrepareHeader( hWaveOut, lpWaveOutHdr$ , uSize )
10730 assign "winmm.dll" , "waveOutPrepareHeader"
10740 END SUB
10750 CALL waveOutPrepareHeader(hWaveOut, header1$, SizeOfWAVEHDR)
10760 END SUB
10770 EXTERNAL SUB DeviceClose
10780 SUB waveOutReset(hWaveOut)
10790 assign "winmm.dll" ,"waveOutReset"
10800 END SUB
10810 SUB waveOutUnprepareHeader( hWaveOut, lpWaveOutHdr$ , uSize )
10820 assign "winmm.dll" , "waveOutUnprepareHeader"
10830 END SUB
10840 SUB waveOutClose(hWaveOut)
10850 assign "winmm.dll" ,"waveOutClose"
10860 END SUB
10870 CALL waveOutReset(hWaveOut)
10880 CALL waveOutUnprepareHeader(hWaveOut, header1$, SizeOfWAVEHDR)
10890 call waveOutClose(hWaveOut)
10900 END SUB
10910 EXTERNAL SUB WaveOut0(w())
10920 SUB waveOutWrite(hWaveOut, header$, SizeOfWAVEHDR)
10930 assign "winmm.dll" ,"waveOutWrite"
10940 END SUB
10950 DECLARE NUMERIC i
10960 FOR i=1 TO BufferLength
10970 LET buffer1$(i*2-1: i*2) = WORD$(32767*w(i))
10980 NEXT i
10990 CALL waveOutWrite(hWaveOut, header1$, SizeOfWAVEHDR)
11000 DECLARE NUMERIC WHDR_DONE
11010 DECLARE EXTERNAL FUNCTION DWord
11020 LET WHDR_DONE=1
11030 DO WHILE BITAND(DWord(header1$,24), WHDR_DONE)=0 !header1$(24:27)はdwFlags
11040 WAIT DELAY 0.01
11050 LOOP
11060 END SUB
11070 END MODULE
11080 EXTERNAL FUNCTION VarPtr(s$)
11090 OPTION ARITHMETIC NATIVE
11100 OPTION CHARACTER byte
11110 FUNCTION CharPrev(s$,t$)
11120 ASSIGN "user32.dll","CharPrevA"
11130 END FUNCTION
11140 LET VarPtr=CharPrev(s$,s$)
11150 END FUNCTION
11160 EXTERNAL FUNCTION DWord(s$,p)
11170 OPTION ARITHMETIC NATIVE
11180 OPTION CHARACTER byte
11190 DECLARE NUMERIC n, i
11200 LET n=0
11210 FOR i=1 TO 4
11220 LET n=n+256^(i-1)*ORD(s$(p+i:p+i))
11230 NEXT i
11240 LET Dword=n
11250 END FUNCTION
11260 EXTERNAL FUNCTION QWord(s$,p)
11270 OPTION ARITHMETIC NATIVE
11280 OPTION CHARACTER byte
11290 DECLARE NUMERIC n, i
11300 LET n=0
11310 FOR i=1 TO 8
11320 LET n=n+256^(i-1)*ORD(s$(p+i:p+i))
11330 NEXT i
11340 LET Qword=n
11350 END FUNCTION
11360 EXTERNAL FUNCTION QWORD$(n)
11370 OPTION CHARACTER BYTE
11380 DECLARE NUMERIC r
11390 DECLARE STRING s$
11400 LET r=MOD(n,2^8)
11410 LET s$=CHR$(r)
11420 LET n=(n-r)/2^8
11430 LET r=MOD(n,2^8)
11440 LET s$=s$ & CHR$(r)
11450 LET n=(n-r)/2^8
11460 LET r=MOD(n,2^8)
11470 LET s$=s$ & CHR$(r)
11480 LET n=(n-r)/2^8
11490 LET r=MOD(n,2^8)
11500 LET s$=s$ & CHR$(r)
11510 LET n=(n-r)/2^8
11520 LET r=MOD(n,2^8)
11530 LET s$=s$ & CHR$(r)
11540 LET n=(n-r)/2^8
11550 LET r=MOD(n,2^8)
11560 LET s$=s$ & CHR$(r)
11570 LET n=(n-r)/2^8
11580 LET r=MOD(n,2^8)
11590 LET s$=s$ & CHR$(r)
11600 LET n=(n-r)/2^8
11610 LET r=MOD(n,2^8)
11620 LET QWORD$=s$ & CHR$(r)
11630 END FUNCTION
Windows APIを利用する上で難しいのが,11030行で利用しているWHDR_DONEなどの定数の実際の数値です。
最近はGoogleに尋ねれば大方解決するようになって大分助かっています。
あと難しいのは構造体の実際の配置です。隙間なく埋まっている場合は計算できますが,そうなっていないこともあるので難しいです(情報が足りない)。
Re: Windowsで音を出力する - knoike
2026/08/01 (Sat) 07:50:43
白石先生
> Windows APIを利用する上で難しいのが,11030行で利用しているWHDR_DONEなどの定数の実際の数値です。
> あと難しいのは構造体の実際の配置です。隙間なく埋まっている場合は計算できますが,そうなっていないこともあるので難しいです(情報が足りない)。
どちらも、Visual C++ をインストールして、それらが定義されているヘッダファイルを探して読めばよいのですが、個人的にはまったくおすすめできません。
白石先生も承知していると思いますが、危ないからです。
また、構造体のメンバのバイトオーダーやアライメントはヘッダファイルを読んでもわからず、コンパイラの振る舞いを想定しておく必要があります。
Win32API を直に使うことは、可能ではあるけれど非推奨、とするほうがよいのではないでしょうか。
ご投稿の主旨が変わってしまいますが、
.dll, .so を作って Win/mac/Linux 共通の関数インターフェースで拡張する方法を解説し、
それを推奨する方針のほうがよいのではないでしょうか。
Windows 環境用に .dll の作り方や使い方、
RPi 環境用に .so の使い方が書かれた情報は存在しますが、
たぶん、これらだけでは macOS 環境の方や Linux 環境の方はわからない(伝わらない)と思います。
「(仮称)十進BASICで自作DLLを使う」
https://decimalbasic.web.fc2.com/MakeDLL.htm
「Win32 APIとDLLの利用」
https://decimalbasic.web.fc2.com/ExtDLL.htm
「Raspberry PiのGPIOを操作する」
https://decimalbasic.web.fc2.com/GPIO_RaspberryPi.htm
「Raspberry Pi GPIO」
https://deimal-basic.bbs.fc2.com/?act=reply&tid=8920538
Re: Windowsで音を出力する - knoike
2026/08/01 (Sat) 08:23:58
どちらの投稿へのリプライにするか迷いましたが、こちらにしておきます。
「Win32 API を使うための情報源」
https://deimal-basic.bbs.fc2.com/?act=reply&tid=8957149
この↑白石先生のご投稿とも関係がありますが、新し目の Visual C++ をインストールしてヘッダファイルを読んだほうが確実です。
実際の手順は、こんな感じ↓です。
Visual C++ を起動し、[ツール] → [コマンドライン] で、「開発者コマンドプロンプト」を起動する。
Windows API のヘッダファイルファイルのあるフォルダへ cd する。
「
C:\Users\kenzi\source\repos>where $include:windows.h
C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\Windows.h
C:\Users\kenzi\source\repos>cd C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\
」
定数 WHDR_DONE の値を調べる。
「
C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um>findstr /S /N WHDR_DONE *.h
mmeapi.h:92:#define WHDR_DONE 0x00000001 /* done bit */
」
構造体 wavehdr_tag(WAVEHDR)の定義を調べる。
「
C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um>findstr /S /N wavehdr *.h
mmeapi.h:80:typedef struct wavehdr_tag {
mmeapi.h:87: struct wavehdr_tag FAR *lpNext; /* reserved for driver */
」
→
mmeapi.h の 80行目あたりだとわかるので、Visual C++ で mmeapi.h を開いて wavehdr で検索してそのあたりを見る。
→
「
/* wave data block header */
typedef struct wavehdr_tag {
LPSTR lpData; /* pointer to locked data buffer */
DWORD dwBufferLength; /* length of data buffer */
DWORD dwBytesRecorded; /* used for input only */
DWORD_PTR dwUser; /* for client's use */
DWORD dwFlags; /* assorted flags (see defines) */
DWORD dwLoops; /* loop control counter */
struct wavehdr_tag FAR *lpNext; /* reserved for driver */
DWORD_PTR reserved; /* reserved for driver */
} WAVEHDR, *PWAVEHDR, NEAR *NPWAVEHDR, FAR *LPWAVEHDR;
」
くどいようですが、10進BASIC から Win32API を直に使うのは、私は非推奨にしたほうがよいと思います。
.dll, .so 経由で使うことを推奨したほうがよいと思います。
Re: Windowsで音を出力する - SHIRAISHI Kazuo
2026/08/03 (Mon) 07:06:42
DLLを自分で作るような人は別ですが,素性が不明なDLLを使うのは,Win32 APIを使うよりさらに多難です。
Win32 APiのほうが仕様が明確で,確実に使えます。
難しいのは,その仕様を効率よく調べる手段が提供されていないからです(普通の人はヘッダファイルを探索するなんてやりたいと思わない)。
Re: Windowsで音を出力する - knoike
2026/08/04 (Tue) 01:28:11
素性が不明な Webページを紹介するくらいだったら、
公式サイトからの情報の探し方を教えてあげてください。
そのほうが、仕様が明確にわかり、最新の情報なので確実に使えます。
Google検索を使うのは公式情報のありかを探すためだけに使いましょう。
白石先生がここ↓で紹介している Webページだって、
https://deimal-basic.bbs.fc2.com/?act=reply&tid=8957149
素性が不明の人が GitHub上の公式情報をクロールしているだけのことです。
それとも、このページを生成している人は白石先生のお知り合いで、
悪さを絶対にしないことが確実に言える人なのですか?
素性だの確実性だのを気にするのであれば、
元をあたりましょうよ、元を。
> まず,waveOutOpen
> https://learn.microsoft.com/ja-jp/windows/win32/api/mmeapi/nf-mmeapi-waveoutopen
> を実行してオーディオデバイスのハンドルを取得します(10470行)。
こんな感じで、公式情報の読み方や探し方を教えてあげてください。
そのほうが確実で、あとで白石先生自身が楽をできます。
あるいは、「公式情報は難しくて読みこなせない」という人向けには、
「ChatGPTなどの対話系の生成AIに訊く」ということを教えてあげてください。
わからないことは次々と訊けば答えてくれるので、
API の使い方や仕様など、あっという間に理解できます。
確実性を担保したいのであれば、そのあとで公式サイトで確認するように伝えておくとよいです。
ChatGPT でなく Claude(Codeは使わない)でもよいです。
> 難しいのは,その仕様を効率よく調べる手段が提供されていないからです
そこがよくわかりません。
Web検索だけでなんとかすることに固執せず、
「ChatGPTなどの対話系の生成AIに訊く」
でよいと思います。いわゆる「普通の人」ならなおさらです。
> (普通の人はヘッダファイルを探索するなんてやりたいと思わない)。
ちょっと Win32API を使ってみたいだけの人ならそうでしょうが、
効率だの確実性だのを望むのであれば、
・公式サイトを検索する
・ローカルでヘッダファイルを検索する
のが圧倒的に効率がよく、しかも確実です。
"探索" なんてしません。findstr で "検索" するだけです。
即座に確実な情報が見つかります。
また、Web検索と違ってゴミ情報を掴まされることが絶対にありません。
Re: Windowsで音を出力する - knoike
2026/08/04 (Tue) 01:40:59
> 素性が不明なDLLを使うのは,Win32 APIを使うよりさらに多難です。
Win32API を呼ぶための Wrapper DLL を、公式が正式に用意する、
という方法もありますが、
かける労力の割にはあまり報われないでしょうね。
そもそも、Wrapper 経由だと、すべての API は使えないです。
ということで、やはり「使用可能だけれども非推奨」にしておいたほうがよいと思います。
白石先生の実装を読んでいませんが、
引数のチェックなどをせずに、素通しで渡してしまっているのではないでしょうか。
Wrapper 経由ならそのチェックができ、問われる責任をある程度回避できます。
無責任に Win32API を直に使わせるのとはかなり違います。
Re: Windowsで音を出力する - knoike
2026/08/04 (Tue) 02:42:42
話は逸れますが、
WASAPI で音を出すことは 10進BASIC からできそうでしょうか。
白石先生が書いたコードは、MME です。
Re: Windowsで音を出力する - SHIRAISHI Kazuo
2026/08/04 (Tue) 19:27:54
Win32 APIを利用する機能(ASSIGN文)は,Full BASICの機能だけでカバーできない部分(ファイル操作・ディレクトリ操作など)を外部に委譲することを目的として,
WIN32 APIの呼び出し規約に準拠するように用意したものです。
なので,ターゲットはWin32 APIです。CDECのDLLは,使えてしまうこともありますが,本来,対象外です(Ver.7 のとき)。
最近のバージョンではファイルやディレクトリ操作などが独自拡張機能でできるようになっているのでWin32 APIの出番はなくなっていますが,
Windowsの機能のすべてを取り込んでいるわけではないので,Win32 APIが不要になったわけではありません。
残す目的は,十進BASICの言語仕様の範囲でできないことを実現することです。
ただし,Win32 APIのすべてが使えるわけではありません。CallBack関数を要求される場合には,うまく対応できないこともあります。
ASSIGN文でできることは,数値型の引数を32ビット整数として評価して渡すことと,文字列型のとき,1文字目へのポインタ(空文字列のときはnul)を渡すことだけです。
数値型変数を参照渡しにすることはできず,浮動小数点数を渡すこともできません。
内部構造が他の多くのシステム開発言語と大きく異なるので,システム開発言語のような感覚でWin32 APIを使うことはできません。
Re: Windowsで音を出力する - knoike
2026/08/09 (Sun) 06:56:41
> 文字列型のとき,1文字目へのポインタ(空文字列のときはnul)を渡す
「素通しにしておらず、アドレス範囲のチェックをしてある」ということでしょうか。
つまり、セキュリティホールになることはない、ということでしょうか。
うーん、ここを見るようになってからまだ日が浅いせいもあり、
いま一歩、白石先生の考える十進BASICのポリシーがわからないので教えてください。
その説明だと、やはり、Win32 API を使うことは「非推奨」なのではないでしょうか。
非常手段として用意してあるだけのことで。
たとえば、「ファイルを介さずにサウンド出力をする」のは、
現時点では公式に(拡張)機能として用意できていないだけのことで、
本来は一般ユーザーに Win32 API を直に使わせる案件ではないのではないでしょうか。
> Win32 APIが不要になったわけではありません
たとえば、どんなことをするために一般ユーザーが Win32 API を直に使う必要があるのでしょうか。
.dll/.dylib/.so を読み込んで使えるようにする機能をなくせ、と言っているわけでは
ありません。この機能自体はあったほうがよいと思います。
たとえば、どこかに AquesTalk の .dll を読み込んで音声合成をさせる例がありましたが、
機能を拡張するために必要な機能です。
私が言語設計者だったら、
何かの処理を Win32 API を使ってしのぐ例を紹介するときは必ず、
「Win32 API を直に使う方法は非推奨です。
可能であれば .dll 化し、ソースコードとともに公開してください」
と添えます。
余談:
いま気づいたのですが、"Win32API" は、昔と違っていまの時代は "Win32 API" と
空白文字で区切るのですね。
公式がそういう変更をするのはナシだなぁ... 。
"DirectX" や "WASAPI" も、そのうち "Dirext X" や "WAS API" に変わるのだろうか... 。
Re: Windowsで音を出力する - SHIRAISHI Kazuo
2026/08/09 (Sun) 08:54:42
十進BASICはシステム開発言語ではありません。しかし,Full BASIC言語仕様でカバーできないことが実行できないのは不便です。
十進BASIC Ver.7のDLL呼び出しはWin32 APIの仕様に合わせてあります。だから「Win32 API非推奨」はありえません。
DLL呼び出しは使い方を間違えると危険です。試行錯誤で使えるものではありません。DLL呼び出しには慎重さが必要です。
Win32 APIは,仕様が明確です。正しく使う限り,期待した通りに動作します。その意味で,Win32 APIで簡単に実現できることにはWin32 APIを使うことが推奨できます。
ただし,Win32 APIはパラメータが多くてそれらの意味を理解するのは容易ではなく,また,使うのにも面倒な手順が必要です。
Win32 APIを使わずに済むのであれば,使わずに済ませたいのは確かです。
Re: Windowsで音を出力する - knoike
2026/08/09 (Sun) 09:40:09
白石先生、次回以降から書き込むときには、
ほどほどの文字数で改行してください。
ブラウザ端で見切れた書き込みを読み出すのが少々手間です。
> CDECのDLLは,使えてしまうこともありますが,
念のために確認しますが、
"CDEC" は "cdecl" のことですよね?
要は対象としているのは cdecl ではなく stdcall ですよ、
ということですよね。
呼び出し側が stdcall を想定して cdecl の .dll 内関数を使うと、
その場では動くでしょうけれど、呼び出すたびにスタックポインタが
ずれていって、あるとき唐突に問題が発生しそう... 。
かといって、呼び出し側で、呼び出される .dll が stdcall かそれ以外かを
確実に判定する方法はなさそうですね。
経験的に「たぶん stdcall だろう」と判断することはできそうですけれど、
不確実な方法です。
それはそうとして、いま、調べていて知ったのですが、
64bit Windows 環境だと、この種の違いがなくなって
問題が起こらなくなったのですね。
cdecl や stdcall などの呼び出し方法の違いは、
「Microsoft x64 calling convention」なる名称の
呼び出し方に統一され、吸収されたのだそうです。
Re: Windowsで音を出力する - knoike
2026/08/09 (Sun) 10:13:51
1/
> > 文字列型のとき,1文字目へのポインタ(空文字列のときはnul)を渡す
>
> 「素通しにしておらず、アドレス範囲のチェックをしてある」ということでしょうか。
> つまり、セキュリティホールになることはない、ということでしょうか。
2/
> たとえば、「ファイルを介さずにサウンド出力をする」のは、
> 現時点では公式に(拡張)機能として用意できていないだけのことで、
> 本来は一般ユーザーに Win32 API を直に使わせる案件ではないのではないでしょうか。
3/
> たとえば、どんなことをするために一般ユーザーが Win32 API を直に使う必要があるのでしょうか。
白石先生、(可能であれば)この 3つの質問に答えてください。
> 十進BASICはシステム開発言語ではありません。しかし,Full BASIC言語仕様でカバーできないことが実行できないのは不便です。
> 十進BASIC Ver.7のDLL呼び出しはWin32 APIの仕様に合わせてあります。だから「Win32 API非推奨」はありえません。
> DLL呼び出しは使い方を間違えると危険です。試行錯誤で使えるものではありません。DLL呼び出しには慎重さが必要です。
> Win32 APIは,仕様が明確です。正しく使う限り,期待した通りに動作します。その意味で,Win32 APIで簡単に実現できることにはWin32 APIを使うことが推奨できます。
> ただし,Win32 APIはパラメータが多くてそれらの意味を理解するのは容易ではなく,また,使うのにも面倒な手順が必要です。
> Win32 APIを使わずに済むのであれば,使わずに済ませたいのは確かです。
読みましたが、この説明であれば、私の感覚だと、
ますます一般ユーザーに対しては「非推奨」です。
「使えるようにしてある」ことと、「それを使うことが推奨されるかどうか」は別の話です。
> 十進BASIC Ver.7のDLL呼び出しはWin32 APIの仕様に合わせてあります。だから「Win32 API非推奨」はありえません。
ここは、"だから" では論理的につながりません。
「~の仕様に合わせてあります。でも危険なので、~を使うことは非推奨です。」
とも言えるでしょう?
しかも、白石先生の想定しているユーザーは、
「Visual C++ をインストールしていない、させたくもない。
Web検索だけでなんとかしようとしている」
というユーザーだったはずです。
「Win32 API は、使えるようにはしてあるけれど、
生半可な知識では使わないでね。つまり、非推奨です。」
これでいいと思うのですがー。
お互いに「自分のほうが状況にあった適切な事柄を提案している」と
思い込んでいるので、論理的に折り合いがつかなそうですね。
ただ、この場は白石先生の場ですので、なるべくなら、私のほうが引くことで終わりたいです。
Re: Windowsで音を出力する - SHIRAISHI Kazuo
2026/08/09 (Sun) 10:35:55
32ビットWindowsだと,C言語ではcdeclが普通で,Win32 APIはstdcallです。
十進BASIC Ver.7 が対応しているのはstdcallです。
ただし,ASSIGN文の実行途中でDelphiの例外処理try~except~endを使っているためか,DLLがスタックポインタを元に戻さないときには元に戻されてしまい,意図した通りには動作しません。
でも,結果的に,cdeclのDLLでも動くことになります。だから,cdeclのDLLは動くかもしれないけれど,非推奨です。
64ビットWindowsだとMicrosoft x64 calling conventionで統一されて厄介な問題は減っているのですが,Linuxなど他のOSとの互換性がない点が面倒です(使う側はあまり気にしなくてよい)。