|
| 1 | +import ctypes |
| 2 | +from ctypes import byref, create_string_buffer, c_int, c_long, c_byte, POINTER, sizeof |
| 3 | +from win32api import Sleep |
| 4 | +from numpy import sin, tan, cos, sqrt |
| 5 | +from math import floor, ceil |
| 6 | +from numpy import log as ln |
| 7 | +from functools import partial |
| 8 | + |
| 9 | +class Infix(object): |
| 10 | + def __init__(self, func): self.func = func |
| 11 | + def __or__(self, other): return self.func(other) |
| 12 | + def __ror__(self, other): return Infix(partial(self.func, other)) |
| 13 | + def __call__(self, v1, v2): return self.func(v1, v2) |
| 14 | +LPSTR,BYTE,WORD,UINT,DWORD,HANDLE=ctypes.c_char_p,ctypes.c_byte,ctypes.c_ushort,ctypes.c_uint,ctypes.c_ulong,ctypes.c_void_p |
| 15 | +HWAVEOUT,LPHWAVEOUT = HANDLE,POINTER(HWAVEOUT) |
| 16 | +winmm = ctypes.windll.Winmm |
| 17 | +waveOutOpen,waveOutPrepareHeader,waveOutWrite,waveOutUnprepareHeader,waveOutClose=winmm.waveOutOpen,winmm.waveOutPrepareHeader,winmm.waveOutWrite,winmm.waveOutUnprepareHeader,winmm.waveOutClose |
| 18 | +WAVE_FORMAT_PCM,WAVE_MAPPER,CALLBACK_NULL=1,-1,0 |
| 19 | + |
| 20 | +class WAVEFORMATEX(ctypes.Structure): |
| 21 | + _fields_ = [ |
| 22 | + ("wFormatTag", WORD), |
| 23 | + ("nChannels", WORD), |
| 24 | + ("nSamplesPerSec", DWORD), |
| 25 | + ("nAvgBytesPerSec", DWORD), |
| 26 | + ("nBlockAlign", WORD), |
| 27 | + ("wBitsPerSample", WORD), |
| 28 | + ("cbSize", WORD) |
| 29 | + ] |
| 30 | +LPWAVEFORMATEX = POINTER(WAVEFORMATEX) |
| 31 | +class WAVEHDR(ctypes.Structure): |
| 32 | + pass |
| 33 | +LPWAVEHDR = POINTER(WAVEHDR) |
| 34 | +WAVEHDR._fields_ = [ |
| 35 | + ("lpData", LPSTR), |
| 36 | + ("dwBufferLength", DWORD), |
| 37 | + ("dwBytesRecorded", DWORD), |
| 38 | + ("dwUser", DWORD), |
| 39 | + ("dwFlags", DWORD), |
| 40 | + ("dwLoops", DWORD), |
| 41 | + ("lpNext", LPWAVEHDR), |
| 42 | + ("reserved", DWORD) |
| 43 | +] |
| 44 | +LPWAVEHDR = POINTER(WAVEHDR) |
| 45 | +division_key_fix=Infix(lambda x,y: x/y if y else 0) |
| 46 | +operand_key_fix=Infix(lambda x,y: int(x)|int(y)) |
| 47 | +charcodeat_key_fix=Infix(lambda s,y: ord(s[y])) |
| 48 | +operand_gtgt_key_fix=Infix(lambda x,y: int(x)>>int(y)) |
| 49 | +operand_ltlt_key_fix=Infix(lambda x, y: int(x)<<int(y)) |
| 50 | + |
| 51 | +class ByteBeat: |
| 52 | + def GenerateBuffer(EQUATION, SECONDS_PLAYING, AMOUNT_KILOHERTZ=8000): |
| 53 | + ''' |
| 54 | + > GenerateBuffer function |
| 55 | + - Generates buffering data playable via the PlayFromBuffer function |
| 56 | + @ EQUATION argument: Mathematical ByteBeat input eg. 't%0.86*t' |
| 57 | + @ EQUATION type: str |
| 58 | + @ SECONDS_PLAYING argument: The length of the ByteBeat, in seconds |
| 59 | + @ SECONDS_PLAYING type: int |
| 60 | + @ AMOUNT_KILOHERTZ argument: The amount of kilohertz (kHz) the ByteBeat will use. |
| 61 | + @ AMOUNT_KILOHERTZ type: int |
| 62 | + ''' |
| 63 | + EQUATION = EQUATION.replace('^','**').replace('random()','__import__("random").random()').replace('|','|operand_key_fix|').replace('/','|division_key_fix|').replace('?',' if ').replace(':',' else ').replace('.charCodeAt',' |charcodeat_key_fix| ').replace('>>',' |operand_gtgt_key_fix| ').replace('<<',' |operand_ltlt_key_fix| ') |
| 64 | + hWaveOut = HWAVEOUT(0) |
| 65 | + wfx = WAVEFORMATEX(WAVE_FORMAT_PCM, 1, AMOUNT_KILOHERTZ, AMOUNT_KILOHERTZ, 1, 8,0) |
| 66 | + waveOutOpen(byref(hWaveOut), WAVE_MAPPER, LPWAVEFORMATEX(wfx), 0, 0, CALLBACK_NULL) |
| 67 | + buffer = create_string_buffer(int(AMOUNT_KILOHERTZ) * SECONDS_PLAYING) |
| 68 | + for t in range(0, int(AMOUNT_KILOHERTZ) * SECONDS_PLAYING):buffer.value += c_byte(int(eval(EQUATION))) |
| 69 | + return buffer.raw |
| 70 | + |
| 71 | + def Play(EQUATION, SECONDS_PLAYING, AMOUNT_KILOHERTZ, ASYNC_SLEEP = False): |
| 72 | + ''' |
| 73 | + > Play function |
| 74 | + - Generates buffering data and plays the result when it finished. |
| 75 | + @ EQUATION argument: Mathematical ByteBeat input eg. 't%0.86*t' |
| 76 | + @ EQUATION type: str |
| 77 | + @ SECONDS_PLAYING argument: The length of the ByteBeat, in seconds |
| 78 | + @ SECONDS_PLAYING type: int |
| 79 | + @ AMOUNT_KILOHERTZ argument: The amount of kilohertz (kHz) the ByteBeat will use. |
| 80 | + @ AMOUNT_KILOHERTZ type: int |
| 81 | + @ ASYNC_SLEEP argument: Wait until the sound playing has finished or not. |
| 82 | + @ ASYNC_SLEEP type: bool |
| 83 | + ''' |
| 84 | + EQUATION = EQUATION.replace('^','**').replace('random()','__import__("random").random()').replace('|','|operand_key_fix|').replace('/','|division_key_fix|').replace('?',' if ').replace(':',' else ').replace('.charCodeAt',' |charcodeat_key_fix| ').replace('>>',' |operand_gtgt_key_fix| ').replace('<<',' |operand_ltlt_key_fix| ') |
| 85 | + hWaveOut = HWAVEOUT(0) |
| 86 | + wfx = WAVEFORMATEX(WAVE_FORMAT_PCM, 1, AMOUNT_KILOHERTZ, AMOUNT_KILOHERTZ, 1, 8,0) |
| 87 | + winmm.waveOutOpen.argtypes = (LPHWAVEOUT, UINT, LPWAVEFORMATEX, DWORD, DWORD, DWORD) |
| 88 | + waveOutOpen(byref(hWaveOut), WAVE_MAPPER, LPWAVEFORMATEX(wfx), 0, 0, CALLBACK_NULL) |
| 89 | + buffer = create_string_buffer(int(AMOUNT_KILOHERTZ) * SECONDS_PLAYING) |
| 90 | + for t in range(0, int(AMOUNT_KILOHERTZ) * SECONDS_PLAYING):buffer.value += c_byte(int(eval(EQUATION))) |
| 91 | + buffer = buffer.raw |
| 92 | + wHeader = WAVEHDR(buffer, len(buffer), 0, 0, 0, 0) |
| 93 | + waveOutPrepareHeader(hWaveOut, byref(wHeader), sizeof(WAVEHDR)) |
| 94 | + waveOutWrite(hWaveOut, byref(wHeader), sizeof(WAVEHDR)) |
| 95 | + waveOutUnprepareHeader(hWaveOut, byref(wHeader), sizeof(WAVEHDR)) |
| 96 | + waveOutClose(hWaveOut) |
| 97 | + if ASYNC_SLEEP: Sleep(SECONDS_PLAYING*1000) |
| 98 | + return True |
| 99 | + def PlayFromBuffer(buffer, SECONDS_PLAYING, AMOUNT_KILOHERTZ, ASYNC_SLEEP=False): |
| 100 | + ''' |
| 101 | + > PlayFromBuffer function |
| 102 | + - Plays buffering data generatable using the GenerateBuffer function |
| 103 | + @ buffer argument: String buffering data |
| 104 | + @ buffer type: str |
| 105 | + @ SECONDS_PLAYING argument: The length of the ByteBeat, in seconds |
| 106 | + @ SECONDS_PLAYING type: int |
| 107 | + @ AMOUNT_KILOHERTZ argument: The amount of kilohertz (kHz) the ByteBeat will use |
| 108 | + @ AMOUNT_KILOHERTZ type: int |
| 109 | + @ ASYNC_SLEEP argument: Wait until the sound playing has finished or not |
| 110 | + @ ASYNC_SLEEP type: bool |
| 111 | + ''' |
| 112 | + hWaveOut = HWAVEOUT(0) |
| 113 | + wfx = WAVEFORMATEX(WAVE_FORMAT_PCM, 1, AMOUNT_KILOHERTZ, AMOUNT_KILOHERTZ, 1, 8,0) |
| 114 | + waveOutOpen(byref(hWaveOut), WAVE_MAPPER, LPWAVEFORMATEX(wfx), 0, 0, CALLBACK_NULL) |
| 115 | + wHeader = WAVEHDR(buffer, len(buffer), 0, 0, 0, 0) |
| 116 | + waveOutPrepareHeader(hWaveOut, byref(wHeader), sizeof(WAVEHDR)) |
| 117 | + waveOutWrite(hWaveOut, byref(wHeader), sizeof(WAVEHDR)) |
| 118 | + waveOutUnprepareHeader(hWaveOut, byref(wHeader), sizeof(WAVEHDR)) |
| 119 | + waveOutClose(hWaveOut) |
| 120 | + if ASYNC_SLEEP: Sleep(SECONDS_PLAYING*1000) |
| 121 | + return True |
0 commit comments