はじめに
ctypesパッケージを使ってWindows APIを呼び出すサンプルとしてサウンドを再生してみた。
ソース
短縮版
winsound版
beep3.py
import struct
import winsound
data = b"\x90\x90\x70\x70" * 500 + b"\x90\x90\x90\x90\x70\x70\x70\x70" * 250
buf = struct.pack("<4sL4s" "4sLHHLLHH" "4sL",
b"RIFF", 36 + len(data), b"WAVE",
b"fmt ", 16, 1, 1, 8000, 8000, 1, 8,
b"data", len(data)) + data
winsound.PlaySound(buf, winsound.SND_MEMORY)
winmm.sndPlaySound版
beep4.py
import struct
import ctypes
winmm = ctypes.windll.winmm
SND_SYNC = 0x0000
SND_MEMORY = 0x0004
data = b"\x90\x90\x70\x70" * 500 + b"\x90\x90\x90\x90\x70\x70\x70\x70" * 250
buf = struct.pack("<4sL4s" "4sLHHLLHH" "4sL",
b"RIFF", 36 + len(data), b"WAVE",
b"fmt ", 16, 1, 1, 8000, 8000, 1, 8,
b"data", len(data)) + data
winmm.sndPlaySoundA(buf, SND_MEMORY | SND_SYNC)
winmm方式
beep.py
from ctypes import *
from ctypes.wintypes import *
import time
winmm = windll.winmm
WAVE_FORMAT_PCM = 1
WAVE_MAPPER = UINT(-1)
CALLBACK_NULL = 0x0000_0000
class WAVEFORMATEX(Structure):
_fields_ = [
("wFormatTag", WORD),
("nChannels", WORD),
("nSamplesPerSec", DWORD),
("nAvgBytesPerSec", DWORD),
("nBlockAlign", WORD),
("wBitsPerSample", WORD),
("cbSize", WORD),
]
class WAVEHDR(Structure):
_fields_ = [
("lpData", LPSTR),
("dwBufferLength", DWORD),
("dwBytesRecorded", DWORD),
("dwUser", PDWORD),
("dwFlags", DWORD),
("dwLoops", DWORD),
("lpNext", LPVOID),
("reserved", PDWORD),
]
def main():
data = b"\x90\x90\x70\x70" * 500 + b"\x90\x90\x90\x90\x70\x70\x70\x70" * 250
hwo = HANDLE()
wfx = WAVEFORMATEX()
wfx.wFormatTag = WAVE_FORMAT_PCM
wfx.nChannels = 1
wfx.nSamplesPerSec = 8000
wfx.nAvgBytesPerSec = 8000
wfx.nBlockAlign = 1
wfx.wBitsPerSample = 8
wfx.cbSize = 0
winmm.waveOutOpen(byref(hwo), WAVE_MAPPER, wfx, 0, 0, CALLBACK_NULL)
wh = WAVEHDR()
wh.lpData = data
wh.dwBufferLength = len(data)
winmm.waveOutPrepareHeader(hwo, byref(wh), sizeof(wh))
winmm.waveOutWrite(hwo, byref(wh), sizeof(wh))
time.sleep(0.6)
winmm.waveOutReset(hwo)
winmm.waveOutUnprepareHeader(hwo, byref(wh), sizeof(wh))
winmm.waveOutClose(hwo)
main()
winsound方式
beep2.py
import io
import winsound
from ctypes import LittleEndianStructure
from ctypes.wintypes import BYTE, WORD, DWORD
FOURCC = BYTE * 4
WAVE_FORMAT_PCM = 0x0001
class WAVEFORMATEX(LittleEndianStructure):
_fields_ = [
("wFormatTag", WORD),
("nChannels", WORD),
("nSamplesPerSec", DWORD),
("nAvgBytesPerSec", DWORD),
("nBlockAlign", WORD),
("wBitsPerSample", WORD),
]
class WAVEFILEHEADER(LittleEndianStructure):
_fields_ = [
("RIFF_ckid", FOURCC),
("RIFF_cksize", DWORD),
("fccType", FOURCC),
("fmt_ckid", FOURCC),
("fmt_cksize", DWORD),
("wfx", WAVEFORMATEX),
("data_ckid", FOURCC),
("data_cksize", DWORD),
]
def main():
data = b"\x90\x90\x70\x70" * 500 + b"\x90\x90\x90\x90\x70\x70\x70\x70" * 250
data_len = len(data)
wfx = WAVEFORMATEX()
wfx.wFormatTag = WAVE_FORMAT_PCM
wfx.nChannels = 1
wfx.nSamplesPerSec = 8000
wfx.nAvgBytesPerSec = 8000
wfx.nBlockAlign = 1
wfx.wBitsPerSample = 8
wfh = WAVEFILEHEADER()
wfh.RIFF_ckid = FOURCC(*b"RIFF")
wfh.RIFF_cksize = 36 + data_len
wfh.fccType = FOURCC(*b"WAVE")
wfh.fmt_ckid = FOURCC(*b"fmt ")
wfh.fmt_cksize = 16
wfh.wfx = wfx
wfh.data_ckid = FOURCC(*b"data")
wfh.data_cksize = data_len
buf = io.BytesIO()
buf.write(wfh)
buf.write(data)
winsound.PlaySound(buf.getvalue(), winsound.SND_MEMORY)
main()
おまけ
coin.py
import struct
import winsound
SAMPLE_RATE = 48000
theta = 0
def main():
data = bytearray()
tone(data, 83, .1)
tone(data, 88, 1)
wav = struct.pack("<4sL4s" "4sLHHLLHH" "4sL",
b"RIFF", 36 + len(data), b"WAVE",
b"fmt ", 16, 1, 1, SAMPLE_RATE, SAMPLE_RATE, 1, 8,
b"data", len(data)) + data
winsound.PlaySound(wav, winsound.SND_MEMORY)
def tone(data, note, sec):
global theta
freq = 440 * 2**((note - 69) / 12)
len = int(SAMPLE_RATE * sec)
for i in range(len):
h = int(16 * (1 - i / SAMPLE_RATE))
t = theta / SAMPLE_RATE
d = 0x80 + (h if t < .5 else -h)
data.append(d)
theta = (theta + freq) % SAMPLE_RATE
main()