mirror of
https://github.com/m4rcel-lol/python-bytebeat-player.git
synced 2025-12-06 19:13:57 +05:30
Add files via upload
This commit is contained in:
113
bytebeat_play.py
Normal file
113
bytebeat_play.py
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
import ast, argparse, math, sys, wave, struct, subprocess, tempfile, os, platform
|
||||||
|
try:
|
||||||
|
import numpy as _np
|
||||||
|
except ImportError:
|
||||||
|
_np = None
|
||||||
|
try:
|
||||||
|
import sounddevice as _sd
|
||||||
|
except ImportError:
|
||||||
|
_sd = None
|
||||||
|
if platform.system().lower()=="windows":
|
||||||
|
import winsound as _ws
|
||||||
|
os.system("")
|
||||||
|
_Z = {ast.Add,ast.Sub,ast.Mult,ast.Div,ast.FloorDiv,ast.Mod,ast.LShift,ast.RShift,ast.BitOr,ast.BitAnd,ast.BitXor,ast.Pow}
|
||||||
|
_Y = {ast.UAdd,ast.USub,ast.Invert,ast.Not}
|
||||||
|
_C = {"r":"\033[0m","g":"\033[92m","c":"\033[96m","y":"\033[93m","R":"\033[91m","B":"\033[1m"}
|
||||||
|
def _a(n):
|
||||||
|
if isinstance(n,ast.Expression): _a(n.body); return
|
||||||
|
if isinstance(n,ast.BinOp):
|
||||||
|
if type(n.op) not in _Z: raise ValueError(type(n.op).__name__)
|
||||||
|
_a(n.left); _a(n.right); return
|
||||||
|
if isinstance(n,ast.UnaryOp):
|
||||||
|
if type(n.op) not in _Y: raise ValueError(type(n.op).__name__)
|
||||||
|
_a(n.operand); return
|
||||||
|
if isinstance(n,ast.Constant):
|
||||||
|
if not isinstance(n.value,(int,float)): raise ValueError("c")
|
||||||
|
return
|
||||||
|
if isinstance(n,ast.Name):
|
||||||
|
if n.id!='t': raise ValueError(n.id)
|
||||||
|
return
|
||||||
|
if isinstance(n,(ast.Call,ast.Attribute,ast.Compare,ast.BoolOp,ast.IfExp)): raise ValueError(type(n).__name__)
|
||||||
|
if not isinstance(n,(ast.Load,)): raise ValueError(type(n).__name__)
|
||||||
|
def _b(s):
|
||||||
|
s=s.replace("/","//"); p=ast.parse(s,mode='eval'); _a(p); co=compile(p,'<b>','eval')
|
||||||
|
def _e(t):
|
||||||
|
L={'t':int(t)}
|
||||||
|
try:
|
||||||
|
r=eval(co,{"__builtins__":None,'math':math},L); return int(r)
|
||||||
|
except Exception:
|
||||||
|
return 0
|
||||||
|
return _e
|
||||||
|
def _g(f,d=10.0,sr=8000,t0=0):
|
||||||
|
cs=sr//4; n=int(d*sr); tc=n//cs
|
||||||
|
if _np is not None:
|
||||||
|
for i in range(tc):
|
||||||
|
b=t0+i*cs; a=_np.empty(cs,dtype=_np.int16)
|
||||||
|
for j in range(cs):
|
||||||
|
v=f(b+j); a[j]=_np.int16(((int(v)&0xFF)-128)*256)
|
||||||
|
yield i/float(tc),a
|
||||||
|
else:
|
||||||
|
for i in range(tc):
|
||||||
|
b=t0+i*cs
|
||||||
|
ch=[((int(f(b+j))&0xFF)-128)*256 for j in range(cs)]
|
||||||
|
yield i/float(tc),ch
|
||||||
|
def _p(f,d,sr,t0):
|
||||||
|
if _sd is None or _np is None:
|
||||||
|
print(f"{_C['y']}sounddevice not installed — using WAV fallback.{_C['r']}")
|
||||||
|
allv=[]
|
||||||
|
try:
|
||||||
|
for pr,ch in _g(f,d,sr,t0):
|
||||||
|
allv.extend(ch)
|
||||||
|
bar="█"*int(40*pr)+"-"*int(40*(1-pr))
|
||||||
|
print(f"\r{_C['c']}[ {bar} ] {int(pr*100)}%{_C['r']}",end="",flush=True)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print(f"\n{_C['R']}Stopped by user!{_C['r']}")
|
||||||
|
print()
|
||||||
|
_w(allv,sr); return
|
||||||
|
print(f"{_C['B']}{_C['g']}▶ Playing live... Press Ctrl+C to stop.{_C['r']}")
|
||||||
|
st=_sd.OutputStream(samplerate=sr,channels=1,dtype='float32'); st.start()
|
||||||
|
try:
|
||||||
|
for pr,ch in _g(f,d,sr,t0):
|
||||||
|
bar="█"*int(40*pr)+"-"*int(40*(1-pr))
|
||||||
|
print(f"\r{_C['c']}[ {bar} ] {int(pr*100)}%{_C['r']}",end="",flush=True)
|
||||||
|
st.write(ch.astype('float32')/32768.0)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print(f"\n{_C['R']}⏹ Interrupted by user!{_C['r']}")
|
||||||
|
finally:
|
||||||
|
st.stop(); st.close(); print(f"{_C['g']}Done.{_C['r']}")
|
||||||
|
def _w(samps,sr):
|
||||||
|
with tempfile.NamedTemporaryFile(suffix='.wav',delete=False) as t: fn=t.name
|
||||||
|
frames = samps.tobytes() if not isinstance(samps,list) else b''.join(struct.pack('<h',x) for x in samps)
|
||||||
|
with wave.open(fn,'wb') as wf:
|
||||||
|
wf.setnchannels(1); wf.setsampwidth(2); wf.setframerate(sr); wf.writeframes(frames)
|
||||||
|
played=False; sysn=platform.system().lower()
|
||||||
|
if sysn=="windows":
|
||||||
|
try: _ws.PlaySound(fn,_ws.SND_FILENAME); played=True
|
||||||
|
except Exception: pass
|
||||||
|
elif sysn=="darwin":
|
||||||
|
try: subprocess.run(['afplay',fn],check=True); played=True
|
||||||
|
except Exception: pass
|
||||||
|
else:
|
||||||
|
try: subprocess.run(['aplay',fn],check=True); played=True
|
||||||
|
except Exception:
|
||||||
|
try: subprocess.run(['ffplay','-nodisp','-autoexit','-hide_banner','-loglevel','panic',fn],check=True); played=True
|
||||||
|
except Exception: pass
|
||||||
|
if not played: print(f"{_C['y']}Couldn't auto-play. WAV written to: {fn}{_C['r']}")
|
||||||
|
def _m():
|
||||||
|
p=argparse.ArgumentParser(description=""); p.add_argument('file'); p.add_argument('--duration',type=float,default=60.0); p.add_argument('--sr',type=int,default=8000); p.add_argument('--tstart',type=int,default=0)
|
||||||
|
a=p.parse_args()
|
||||||
|
try:
|
||||||
|
with open(a.file,'r') as f: expr=f.read().strip()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{_C['R']}Could not read file:{_C['r']}",e); sys.exit(1)
|
||||||
|
try:
|
||||||
|
ev=_b(expr)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"{_C['R']}Error parsing expression:{_C['r']}",e); sys.exit(1)
|
||||||
|
print(f"{_C['B']}{_C['g']}Bytebeat Player Ready!{_C['r']}")
|
||||||
|
print(f"{_C['c']}Expression:{_C['r']} {expr}")
|
||||||
|
print(f"{_C['c']}Sample Rate:{_C['r']} {a.sr} Hz")
|
||||||
|
print(f"{_C['c']}Duration:{_C['r']} {a.duration:.1f} s\n")
|
||||||
|
_p(ev,a.duration,a.sr,a.tstart)
|
||||||
|
if __name__=='__main__': _m()
|
||||||
2
requirements.txt
Normal file
2
requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
numpy
|
||||||
|
sounddevice
|
||||||
1
salinewin.byteb
Normal file
1
salinewin.byteb
Normal file
@@ -0,0 +1 @@
|
|||||||
|
t * ((t / 2 >> 10 | t % 16 * t >> 8) & 8 * t >> 12 & 18) | -(t >> 4) + 64
|
||||||
Reference in New Issue
Block a user