Files
ap_ds_afs/ap_ds/_sdl2.py
T

1054 lines
36 KiB
Python

# sdl2.py - SDL2 constants, structures, bindings and cross-platform loader
import os
import sys
import tempfile
import shutil
import subprocess
import ssl
import hashlib
import urllib.request
from ctypes import *
# ============================================================
# SDL2 Library Loader
# ============================================================
_sdl_lib = None
_mix_lib = None
def _load_from_directory(directory):
"""Load SDL2 libraries from specified directory"""
global _sdl_lib, _mix_lib
platform = sys.platform
if platform == "win32":
sdl2_path = os.path.join(directory, "SDL2.dll")
sdl2_mixer_path = os.path.join(directory, "SDL2_mixer.dll")
if os.path.exists(sdl2_path) and os.path.exists(sdl2_mixer_path):
if hasattr(os, 'add_dll_directory'):
os.add_dll_directory(directory)
os.environ['PATH'] = directory + os.pathsep + os.environ.get('PATH', '')
_sdl_lib = CDLL(sdl2_path)
_mix_lib = CDLL(sdl2_mixer_path)
return True
return False
elif platform == "darwin":
sdl2_path = os.path.join(directory, "SDL2.framework", "SDL2")
sdl2_mixer_path = os.path.join(directory, "SDL2_mixer.framework", "SDL2_mixer")
if os.path.exists(sdl2_path) and os.path.exists(sdl2_mixer_path):
framework_dir = os.path.dirname(os.path.dirname(sdl2_path))
if 'DYLD_FRAMEWORK_PATH' not in os.environ:
os.environ['DYLD_FRAMEWORK_PATH'] = framework_dir
else:
os.environ['DYLD_FRAMEWORK_PATH'] = framework_dir + ':' + os.environ['DYLD_FRAMEWORK_PATH']
_sdl_lib = CDLL(sdl2_path)
_mix_lib = CDLL(sdl2_mixer_path)
return True
return False
elif platform.startswith("linux"):
names_to_try = [
("libSDL2.so", "libSDL2_mixer.so"),
("SDL2.so", "SDL2_mixer.so"),
]
for sdl_name, mixer_name in names_to_try:
sdl_path = os.path.join(directory, sdl_name)
mixer_path = os.path.join(directory, mixer_name)
if os.path.exists(sdl_path) and os.path.exists(mixer_path):
if 'LD_LIBRARY_PATH' not in os.environ:
os.environ['LD_LIBRARY_PATH'] = directory
else:
os.environ['LD_LIBRARY_PATH'] = directory + ':' + os.environ['LD_LIBRARY_PATH']
_sdl_lib = CDLL(sdl_path)
_mix_lib = CDLL(mixer_path)
return True
return False
return False
def _load_from_system():
"""Try loading from system paths"""
global _sdl_lib, _mix_lib
platform = sys.platform
try:
import ctypes.util
sdl_path = ctypes.util.find_library("SDL2")
mixer_path = ctypes.util.find_library("SDL2_mixer")
if sdl_path and mixer_path:
_sdl_lib = CDLL(sdl_path)
_mix_lib = CDLL(mixer_path)
return True
except:
pass
return False
def _load_user_config():
"""Load user-saved SDL2 paths from config file"""
try:
config_file = os.path.expanduser('~/.config/ap_ds/sdl_paths.conf')
if os.path.exists(config_file):
with open(config_file, 'r') as f:
sdl_path = None
mixer_path = None
for line in f:
if line.startswith('SDL2_PATH='):
sdl_path = line.strip().split('=', 1)[1]
elif line.startswith('SDL2_MIXER_PATH='):
mixer_path = line.strip().split('=', 1)[1]
if sdl_path and mixer_path and os.path.exists(sdl_path) and os.path.exists(mixer_path):
global _sdl_lib, _mix_lib
_sdl_lib = CDLL(sdl_path)
_mix_lib = CDLL(mixer_path)
return True
except:
pass
return False
def _run_sudo_command(cmd, packages):
"""Run a sudo command with interactive password input.
First tries without password (if already root or passwordless sudo).
If that fails, prompts for the sudo password interactively.
Args:
cmd: Base command list (e.g. ['apt-get', 'install', '-y'])
packages: Package names to install
Returns:
bool: True if command succeeded
"""
import subprocess
import getpass
full_cmd = cmd + packages
# Try without password first (if already root / passwordless sudo)
try:
result = subprocess.run(
['sudo', '-n'] + full_cmd,
capture_output=True, text=True, timeout=120
)
if result.returncode == 0:
return True
except Exception:
pass
# Prompt for sudo password interactively
print("🔑 sudo password required for package installation")
try:
password = getpass.getpass("Enter sudo password: ")
except (EOFError, KeyboardInterrupt):
print("\n❌ Password input cancelled")
return False
# Use sudo -S to read password from stdin
try:
result = subprocess.run(
['sudo', '-S'] + full_cmd,
input=password + '\n',
capture_output=True, text=True, timeout=180
)
if result.returncode == 0:
print("✅ Packages installed successfully")
return True
else:
print(f"❌ Installation failed: {result.stderr.strip()}")
return False
except Exception as e:
print(f"❌ Installation error: {e}")
return False
def _linux_auto_install():
"""Try automatic package manager installation on Linux"""
try:
import subprocess
import shutil
if shutil.which('apt-get'):
print("📦 Detected apt-based system (Ubuntu/Debian)")
if _run_sudo_command(['apt-get', 'install', '-y'],
['libsdl2-dev', 'libsdl2-mixer-dev']):
if _load_from_system():
print("✅ SDL2 libraries installed and loaded")
return True
elif shutil.which('dnf'):
print("📦 Detected dnf-based system (Fedora)")
if _run_sudo_command(['dnf', 'install', '-y'],
['SDL2-devel', 'SDL2_mixer-devel']):
if _load_from_system():
print("✅ SDL2 libraries installed and loaded")
return True
elif shutil.which('pacman'):
print("📦 Detected pacman-based system (Arch)")
if _run_sudo_command(['pacman', '-S', '--noconfirm'],
['sdl2', 'sdl2_mixer']):
if _load_from_system():
print("✅ SDL2 libraries installed and loaded")
return True
except Exception as e:
print(f"⚠️ Automatic installation failed: {e}")
return False
def _linux_interactive_setup():
"""Linux interactive setup for SDL2"""
global _sdl_lib, _mix_lib
print("\n" + "="*70)
print("Linux SDL2 Library Loading")
print("="*70)
print("Options:")
print("1. Use system-installed libraries (re-check)")
print("2. Specify path to your compiled .so files")
print("3. Show installation instructions")
print("="*70)
while True:
choice = input("\nChoose option (1/2/3): ").strip()
if choice == "1":
if _load_from_system():
print("✅ SDL2 libraries loaded from system")
return True
print("❌ System libraries not found")
continue
elif choice == "2":
sdl_path = input("Enter full path to libSDL2.so: ").strip()
mixer_path = input("Enter full path to libSDL2_mixer.so: ").strip()
if os.path.exists(sdl_path) and os.path.exists(mixer_path):
try:
_sdl_lib = CDLL(sdl_path)
_mix_lib = CDLL(mixer_path)
# Save for future
try:
config_dir = os.path.expanduser('~/.config/ap_ds')
os.makedirs(config_dir, exist_ok=True)
with open(os.path.join(config_dir, 'sdl_paths.conf'), 'w') as f:
f.write(f"SDL2_PATH={sdl_path}\n")
f.write(f"SDL2_MIXER_PATH={mixer_path}\n")
except:
pass
print("✅ Libraries loaded from user-specified paths")
return True
except Exception as e:
print(f"❌ Failed to load: {e}")
else:
print("❌ One or both files not found")
continue
elif choice == "3":
print("\n📚 Installation instructions:")
print("="*50)
print("For Ubuntu/Debian:")
print(" sudo apt-get install libsdl2-dev libsdl2-mixer-dev")
print("\nFor Fedora:")
print(" sudo dnf install SDL2-devel SDL2_mixer-devel")
print("\nFor Arch:")
print(" sudo pacman -S sdl2 sdl2_mixer")
print("\nManual compilation:")
print("1. Download SDL2 from: https://www.libsdl.org/download-2.0.php")
print("2. Download SDL2_mixer from: https://www.libsdl.org/projects/SDL_mixer/")
print("3. Compile: ./configure && make && sudo make install")
print("="*50)
continue
else:
print("❌ Invalid choice. Please enter 1, 2, or 3.")
def _check_sdl_libraries_exist(directory):
"""Check if SDL2 libraries exist in directory"""
platform = sys.platform
if platform == "win32":
return os.path.exists(os.path.join(directory, "SDL2.dll")) and \
os.path.exists(os.path.join(directory, "SDL2_mixer.dll"))
elif platform == "darwin":
return os.path.exists(os.path.join(directory, "SDL2.framework")) and \
os.path.exists(os.path.join(directory, "SDL2_mixer.framework"))
elif platform.startswith("linux"):
return os.path.exists(os.path.join(directory, "libSDL2.so")) and \
os.path.exists(os.path.join(directory, "libSDL2_mixer.so"))
return False
def _check_sdl2_loaded():
"""Check if SDL2 is already loaded"""
return _sdl_lib is not None and _mix_lib is not None
def download_sdl_libraries():
"""Download SDL2 libraries to package directory based on platform with file hash verification"""
FILE_HASHES = {
"SDL2.dll": "520d0459b91efa32fbccf9027a9ca1fc5aae657e679ce8e90f179f9cf5afd279",
"SDL2_mixer.dll": "2a0fc5e9f72c2eaec3240cb82b7594a58ccda609485981f256b94d0a4dd8d6f8",
"SDL2.dmg": "2bf2cb8f6b44d584b14e8d4ca7437080d1d968fe3962303be27217b336b82249",
"SDL2_mixer.dmg": "d74052391ee4d91836bf1072a060f1d821710f3498a54996c66b9a17c79a72d1",
}
current_dir = os.path.dirname(os.path.abspath(__file__))
print(f"Package directory: {current_dir}")
platform = sys.platform
def download_file(url, expected_hash=None):
temp_file = tempfile.NamedTemporaryFile(delete=False)
temp_file.close()
try:
print(f" Attempting download with SSL verification...")
try:
req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
with urllib.request.urlopen(req, timeout=30) as response:
content = response.read()
print(f" ✅ Download successful with SSL verification")
except (urllib.error.URLError, ssl.SSLError, Exception) as e:
print(f" SSL verification failed: {e}")
print(f" Attempting download without SSL verification...")
context = ssl.create_default_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
with urllib.request.urlopen(req, timeout=30, context=context) as response:
content = response.read()
print(f" ✅ Download successful without SSL verification")
with open(temp_file.name, 'wb') as f:
f.write(content)
print(f" Downloaded {len(content)} bytes")
if expected_hash and expected_hash != "expected_sha256_hash_of_xxx":
file_hash = hashlib.sha256(content).hexdigest()
print(f" File SHA256: {file_hash}")
if file_hash.lower() != expected_hash.lower():
raise Exception(f"Hash verification failed! Expected: {expected_hash}, Got: {file_hash}")
print(f" ✅ Hash verification passed")
else:
print(f" ⚠️ No hash verification (hash not configured)")
return content, temp_file.name
except Exception as e:
print(f" ❌ Download failed: {str(e)}")
try:
os.unlink(temp_file.name)
except:
pass
raise
def verify_file_hash(file_path, expected_hash):
if not expected_hash or expected_hash == "expected_sha256_hash_of_xxx":
print(f" ⚠️ No hash configured for {os.path.basename(file_path)}, skipping verification")
return True
try:
with open(file_path, 'rb') as f:
content = f.read()
file_hash = hashlib.sha256(content).hexdigest()
print(f" Existing file SHA256: {file_hash}")
if file_hash.lower() == expected_hash.lower():
print(f" ✅ Hash verification passed")
return True
else:
print(f" ❌ Hash verification failed! Expected: {expected_hash}, Got: {file_hash}")
return False
except Exception as e:
print(f" ❌ Error verifying hash: {e}")
return False
# Windows
if platform == "win32":
files = [
{"url": "https://dvsyun.top/ap_ds/download/SDL2", "filename": "SDL2.dll", "expected_hash": FILE_HASHES.get("SDL2.dll")},
{"url": "https://dvsyun.top/ap_ds/download/SDL2_M", "filename": "SDL2_mixer.dll", "expected_hash": FILE_HASHES.get("SDL2_mixer.dll")}
]
for file_info in files:
file_path = os.path.join(current_dir, file_info["filename"])
if os.path.exists(file_path):
print(f"\n📁 {file_info['filename']} already exists, verifying hash...")
if verify_file_hash(file_path, file_info["expected_hash"]):
print(f"✅ {file_info['filename']} is valid, skipping download")
continue
else:
print(f"⚠️ {file_info['filename']} hash mismatch, re-downloading...")
try:
os.remove(file_path)
except:
pass
print(f"\n📥 Downloading {file_info['filename']}...")
try:
content, temp_path = download_file(file_info["url"], file_info["expected_hash"])
shutil.move(temp_path, file_path)
print(f"✅ Successfully downloaded {file_info['filename']}")
except Exception as e:
print(f"❌ Failed to download {file_info['filename']}: {str(e)}")
continue
# macOS
elif platform == "darwin":
frameworks = [
{"name": "SDL2", "url": "https://dvsyun.top/ap_ds/download/SDL2/MAC", "dmg_filename": "SDL2.dmg", "framework_name": "SDL2.framework", "expected_hash": FILE_HASHES.get("SDL2.dmg")},
{"name": "SDL2_mixer", "url": "https://dvsyun.top/ap_ds/download/SDL2_M/MAC", "dmg_filename": "SDL2_mixer.dmg", "framework_name": "SDL2_mixer.framework", "expected_hash": FILE_HASHES.get("SDL2_mixer.dmg")}
]
for framework_info in frameworks:
framework_path = os.path.join(current_dir, framework_info["framework_name"])
if os.path.exists(framework_path):
print(f"\n📁 {framework_info['framework_name']} already exists, skipping download")
continue
print(f"\n📥 Downloading {framework_info['dmg_filename']}...")
temp_dmg = None
try:
content, temp_dmg = download_file(framework_info["url"], framework_info["expected_hash"])
print(f"✅ Downloaded {framework_info['dmg_filename']}")
mount_point = tempfile.mkdtemp(prefix=f"{framework_info['name']}_mount_")
try:
cmd = ["hdiutil", "attach", temp_dmg, "-mountpoint", mount_point, "-nobrowse", "-quiet"]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
print(f"❌ Failed to mount {framework_info['dmg_filename']}: {result.stderr}")
continue
framework_src = None
for root, dirs, files in os.walk(mount_point):
if framework_info["framework_name"] in dirs:
framework_src = os.path.join(root, framework_info["framework_name"])
break
if not framework_src:
possible_paths = [
os.path.join(mount_point, framework_info["framework_name"]),
os.path.join(mount_point, framework_info["name"], framework_info["framework_name"]),
os.path.join(mount_point, "Frameworks", framework_info["framework_name"]),
]
for path in possible_paths:
if os.path.exists(path):
framework_src = path
break
if not framework_src:
print(f"❌ Could not find {framework_info['framework_name']} in dmg")
subprocess.run(["hdiutil", "detach", mount_point, "-quiet"])
continue
shutil.copytree(framework_src, framework_path)
print(f"✅ Extracted {framework_info['framework_name']} to package directory")
subprocess.run(["hdiutil", "detach", mount_point, "-quiet"])
except Exception as e:
print(f"❌ Extraction failed: {e}")
try:
subprocess.run(["hdiutil", "detach", mount_point, "-force", "-quiet"])
except:
pass
continue
finally:
if temp_dmg and os.path.exists(temp_dmg):
os.unlink(temp_dmg)
if os.path.exists(mount_point):
try:
os.rmdir(mount_point)
except:
pass
except Exception as e:
print(f"❌ Download failed: {str(e)}")
if temp_dmg and os.path.exists(temp_dmg):
try:
os.unlink(temp_dmg)
except:
pass
continue
# Linux
elif platform.startswith("linux"):
print("\n" + "="*70)
print("⚠️ Linux Support Notice")
print("="*70)
print("For Linux systems, SDL2 libraries are NOT provided via automatic download.")
print("Reason: There are too many Linux distributions and library dependencies.")
print("")
print("To use ap_ds on Linux:")
print("1. Install SDL2 and SDL2_mixer using your package manager:")
print(" - Ubuntu/Debian: sudo apt-get install libsdl2-dev libsdl2-mixer-dev")
print(" - Fedora: sudo dnf install SDL2-devel SDL2_mixer-devel")
print(" - Arch: sudo pacman -S sdl2 sdl2_mixer")
print("2. Or compile from source:")
print(" - Download from: https://www.libsdl.org/")
print(" - Build instructions: https://wiki.libsdl.org/Installation")
print("")
print("After installation, run ap_ds again.")
print("="*70 + "\n")
response = input("Do you have pre-compiled .so files? (y/n): ").strip().lower()
if response == 'y':
sdl2_path = input("Enter full path to libSDL2.so: ").strip()
sdl2_mixer_path = input("Enter full path to libSDL2_mixer.so: ").strip()
if os.path.exists(sdl2_path) and os.path.exists(sdl2_mixer_path):
shutil.copy2(sdl2_path, os.path.join(current_dir, "libSDL2.so"))
shutil.copy2(sdl2_mixer_path, os.path.join(current_dir, "libSDL2_mixer.so"))
print("✅ Libraries copied to package directory")
else:
print("❌ One or both library files not found")
else:
print("Please install SDL2 libraries and try again.")
return
print(f"\n📂 Files in package directory: {os.listdir(current_dir)}")
def import_sdl2():
"""Main function: Import SDL2 libraries with cross-platform support"""
global _sdl_lib, _mix_lib
# Already loaded?
if _check_sdl2_loaded():
return _sdl_lib, _mix_lib
current_dir = os.path.dirname(os.path.abspath(__file__))
platform = sys.platform
# Windows
if platform == "win32":
# Try current directory
if _load_from_directory(current_dir):
print("✅ SDL2 loaded from package directory")
return _sdl_lib, _mix_lib
# Try system path
try:
_sdl_lib = CDLL("SDL2.dll")
_mix_lib = CDLL("SDL2_mixer.dll")
print("✅ SDL2 loaded from system path")
return _sdl_lib, _mix_lib
except:
pass
# Download
print("SDL2 libraries not found, downloading...")
download_sdl_libraries()
if _load_from_directory(current_dir):
print("✅ SDL2 loaded after download")
return _sdl_lib, _mix_lib
raise ImportError("Failed to load SDL2 libraries after download")
# macOS
elif platform == "darwin":
# Try current directory
if _load_from_directory(current_dir):
print("✅ SDL2 loaded from package directory")
return _sdl_lib, _mix_lib
# Try system framework paths
if _load_from_system():
print("✅ SDL2 loaded from system")
return _sdl_lib, _mix_lib
# Download
print("SDL2 frameworks not found, downloading...")
download_sdl_libraries()
if _load_from_directory(current_dir):
print("✅ SDL2 loaded after download")
return _sdl_lib, _mix_lib
raise ImportError("Failed to load SDL2 frameworks after download")
# Linux
elif platform.startswith("linux"):
# Layer 1: Load from current directory
if _load_from_directory(current_dir):
print("✅ SDL2 loaded from package directory")
return _sdl_lib, _mix_lib
# Layer 2: User config
if _load_user_config():
print("✅ SDL2 loaded from user config")
return _sdl_lib, _mix_lib
# Layer 3: System libraries
if _load_from_system():
print("✅ SDL2 loaded from system")
return _sdl_lib, _mix_lib
# Layer 4: Auto install
if _linux_auto_install():
return _sdl_lib, _mix_lib
# Layer 5: Interactive setup
if _linux_interactive_setup():
return _sdl_lib, _mix_lib
raise ImportError("Failed to load SDL2 libraries on Linux")
else:
raise ImportError(f"Unsupported platform: {platform}")
# ============================================================
# SDL2 Constants
# ============================================================
SDL_bool = c_int
SDL_TRUE = 1
SDL_FALSE = 0
SDL_INIT_TIMER = 0x00000001
SDL_INIT_AUDIO = 0x00000010
SDL_INIT_VIDEO = 0x00000020
SDL_INIT_JOYSTICK = 0x00000200
SDL_INIT_HAPTIC = 0x00001000
SDL_INIT_GAMECONTROLLER = 0x00002000
SDL_INIT_EVENTS = 0x00004000
SDL_INIT_EVERYTHING = (SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO |
SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC |
SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS)
AUDIO_U8 = 0x0008
AUDIO_S8 = 0x8008
AUDIO_U16LSB = 0x0010
AUDIO_S16LSB = 0x8010
AUDIO_U16MSB = 0x1010
AUDIO_S16MSB = 0x9010
AUDIO_U16 = AUDIO_U16LSB
AUDIO_S16 = AUDIO_S16LSB
AUDIO_S32LSB = 0x8020
AUDIO_S32MSB = 0x9020
AUDIO_S32 = AUDIO_S32LSB
AUDIO_F32LSB = 0x8120
AUDIO_F32MSB = 0x9120
AUDIO_F32 = AUDIO_F32LSB
if sys.byteorder == 'little':
AUDIO_U16SYS = AUDIO_U16LSB
AUDIO_S16SYS = AUDIO_S16LSB
AUDIO_S32SYS = AUDIO_S32LSB
AUDIO_F32SYS = AUDIO_F32LSB
else:
AUDIO_U16SYS = AUDIO_U16MSB
AUDIO_S16SYS = AUDIO_S16MSB
AUDIO_S32SYS = AUDIO_S32MSB
AUDIO_F32SYS = AUDIO_F32MSB
MIX_DEFAULT_FORMAT = AUDIO_S16SYS
MIX_INIT_FLAC = 0x00000001
MIX_INIT_MOD = 0x00000002
MIX_INIT_MP3 = 0x00000008
MIX_INIT_OGG = 0x00000010
MIX_INIT_MID = 0x00000020
MIX_INIT_OPUS = 0x00000040
MIX_CHANNEL_POST = -2
MIX_DEFAULT_CHANNELS = 2
MUS_NONE = 0
MUS_CMD = 1
MUS_WAV = 2
MUS_MOD = 3
MUS_MID = 4
MUS_OGG = 5
MUS_MP3 = 6
MUS_FLAC = 7
MUS_OPUS = 8
# ============================================================
# SDL2 Structures
# ============================================================
class SDL_AudioSpec(Structure):
_fields_ = [
("freq", c_int),
("format", c_uint16),
("channels", c_uint8),
("silence", c_uint8),
("samples", c_uint16),
("padding", c_uint16),
("size", c_uint32),
("callback", c_void_p),
("userdata", c_void_p)
]
class Mix_Chunk(Structure):
_fields_ = [
("allocated", c_int),
("abuf", POINTER(c_uint8)),
("alen", c_uint32),
("volume", c_uint8)
]
# ============================================================
# SDL2 Function Bindings (set up AFTER loading)
# ============================================================
# These are set up after _sdl_lib and _mix_lib are loaded
# We define them as functions that will use the global _sdl_lib and _mix_lib
def SDL_Init(flags):
return _sdl_lib.SDL_Init(flags)
def SDL_InitSubSystem(flags):
return _sdl_lib.SDL_InitSubSystem(flags)
def SDL_Quit():
_sdl_lib.SDL_Quit()
def SDL_QuitSubSystem(flags):
_sdl_lib.SDL_QuitSubSystem(flags)
def SDL_WasInit(flags):
return _sdl_lib.SDL_WasInit(flags)
def SDL_GetError():
return _sdl_lib.SDL_GetError()
def SDL_RWFromFile(file, mode):
if isinstance(file, str):
file = file.encode('utf-8')
if isinstance(mode, str):
mode = mode.encode('utf-8')
return _sdl_lib.SDL_RWFromFile(file, mode)
def SDL_Delay(ms):
_sdl_lib.SDL_Delay(ms)
def Mix_OpenAudio(frequency, format, channels, chunksize):
return _mix_lib.Mix_OpenAudio(frequency, format, channels, chunksize)
def Mix_CloseAudio():
_mix_lib.Mix_CloseAudio()
def Mix_QuerySpec(frequency, format, channels):
return _mix_lib.Mix_QuerySpec(byref(frequency), byref(format), byref(channels))
def Mix_LoadWAV(file):
if isinstance(file, str):
file = file.encode('utf-8')
return _mix_lib.Mix_LoadWAV_RW(SDL_RWFromFile(file, b"rb"), 1)
def Mix_LoadMUS(file):
if isinstance(file, str):
file = file.encode('utf-8')
return _mix_lib.Mix_LoadMUS_RW(SDL_RWFromFile(file, b"rb"), 1)
def Mix_FreeChunk(chunk):
_mix_lib.Mix_FreeChunk(chunk)
def Mix_FreeMusic(music):
_mix_lib.Mix_FreeMusic(music)
def Mix_PlayChannel(channel, chunk, loops):
return _mix_lib.Mix_PlayChannel(channel, chunk, loops)
def Mix_PlayMusic(music, loops):
return _mix_lib.Mix_PlayMusic(music, loops)
def Mix_Pause(channel):
_mix_lib.Mix_Pause(channel)
def Mix_PauseMusic():
_mix_lib.Mix_PauseMusic()
def Mix_Resume(channel):
_mix_lib.Mix_Resume(channel)
def Mix_ResumeMusic():
_mix_lib.Mix_ResumeMusic()
def Mix_HaltChannel(channel):
return _mix_lib.Mix_HaltChannel(channel)
def Mix_HaltMusic():
return _mix_lib.Mix_HaltMusic()
def Mix_SetMusicPosition(position):
return _mix_lib.Mix_SetMusicPosition(position)
def Mix_MusicDuration(music):
return _mix_lib.Mix_MusicDuration(music)
def Mix_Volume(channel, volume):
return _mix_lib.Mix_Volume(channel, volume)
def Mix_VolumeMusic(volume):
return _mix_lib.Mix_VolumeMusic(volume)
def Mix_AllocateChannels(numchans):
return _mix_lib.Mix_AllocateChannels(numchans)
def Mix_GetMusicType(music):
return _mix_lib.Mix_GetMusicType(music)
def Mix_FadingMusic():
return _mix_lib.Mix_FadingMusic()
def Mix_FadeInMusic(music, loops, ms):
return _mix_lib.Mix_FadeInMusic(music, loops, ms)
def Mix_FadeOutMusic(ms):
return _mix_lib.Mix_FadeOutMusic(ms)
def Mix_FadeInChannel(channel, chunk, loops, ms):
return _mix_lib.Mix_FadeInChannel(channel, chunk, loops, ms)
def Mix_FadeOutChannel(channel, ms):
return _mix_lib.Mix_FadeOutChannel(channel, ms)
def Mix_Playing(channel):
return _mix_lib.Mix_Playing(channel)
def Mix_PlayingMusic():
return _mix_lib.Mix_PlayingMusic()
def Mix_Paused(channel):
return _mix_lib.Mix_Paused(channel)
def Mix_PausedMusic():
return _mix_lib.Mix_PausedMusic()
def Mix_SetPanning(channel, left, right):
return _mix_lib.Mix_SetPanning(channel, left, right)
def Mix_SetDistance(channel, distance):
return _mix_lib.Mix_SetDistance(channel, distance)
def Mix_SetPosition(channel, angle, distance):
return _mix_lib.Mix_SetPosition(channel, angle, distance)
def Mix_SetReverseStereo(channel, flip):
return _mix_lib.Mix_SetReverseStereo(channel, flip)
def Mix_FadeInMusicPos(music, loops, ms, position):
return _mix_lib.Mix_FadeInMusicPos(music, loops, ms, position)
# ============================================================
# Function Prototypes (set after libraries are loaded)
# ============================================================
def _setup_prototypes():
"""Set up function prototypes for SDL2 and SDL2_mixer"""
# SDL function prototypes
_sdl_lib.SDL_Init.argtypes = [c_uint32]
_sdl_lib.SDL_Init.restype = c_int
_sdl_lib.SDL_InitSubSystem.argtypes = [c_uint32]
_sdl_lib.SDL_InitSubSystem.restype = c_int
_sdl_lib.SDL_Quit.argtypes = []
_sdl_lib.SDL_Quit.restype = None
_sdl_lib.SDL_QuitSubSystem.argtypes = [c_uint32]
_sdl_lib.SDL_QuitSubSystem.restype = None
_sdl_lib.SDL_WasInit.argtypes = [c_uint32]
_sdl_lib.SDL_WasInit.restype = c_uint32
_sdl_lib.SDL_GetError.argtypes = []
_sdl_lib.SDL_GetError.restype = c_char_p
_sdl_lib.SDL_RWFromFile.argtypes = [c_char_p, c_char_p]
_sdl_lib.SDL_RWFromFile.restype = c_void_p
_sdl_lib.SDL_Delay.argtypes = [c_uint32]
_sdl_lib.SDL_Delay.restype = None
# SDL_mixer function prototypes
_mix_lib.Mix_OpenAudio.argtypes = [c_int, c_uint16, c_int, c_int]
_mix_lib.Mix_OpenAudio.restype = c_int
_mix_lib.Mix_CloseAudio.argtypes = []
_mix_lib.Mix_CloseAudio.restype = None
if hasattr(_mix_lib, 'Mix_QuerySpec'):
_mix_lib.Mix_QuerySpec.argtypes = [POINTER(c_int), POINTER(c_uint16), POINTER(c_int)]
_mix_lib.Mix_QuerySpec.restype = c_int
if hasattr(_mix_lib, 'Mix_LoadWAV_RW'):
_mix_lib.Mix_LoadWAV_RW.argtypes = [c_void_p, c_int]
_mix_lib.Mix_LoadWAV_RW.restype = POINTER(Mix_Chunk)
if hasattr(_mix_lib, 'Mix_LoadMUS_RW'):
_mix_lib.Mix_LoadMUS_RW.argtypes = [c_void_p, c_int]
_mix_lib.Mix_LoadMUS_RW.restype = c_void_p
if hasattr(_mix_lib, 'Mix_FreeChunk'):
_mix_lib.Mix_FreeChunk.argtypes = [POINTER(Mix_Chunk)]
_mix_lib.Mix_FreeChunk.restype = None
if hasattr(_mix_lib, 'Mix_FreeMusic'):
_mix_lib.Mix_FreeMusic.argtypes = [c_void_p]
_mix_lib.Mix_FreeMusic.restype = None
if hasattr(_mix_lib, 'Mix_FadeInMusicPos'):
_mix_lib.Mix_FadeInMusicPos.argtypes = [c_void_p, c_int, c_int, c_double]
_mix_lib.Mix_FadeInMusicPos.restype = c_int
if hasattr(_mix_lib, 'Mix_PlayChannel'):
_mix_lib.Mix_PlayChannel.argtypes = [c_int, POINTER(Mix_Chunk), c_int]
_mix_lib.Mix_PlayChannel.restype = c_int
elif hasattr(_mix_lib, 'Mix_PlayChannelTimed'):
_mix_lib.Mix_PlayChannelTimed.argtypes = [c_int, POINTER(Mix_Chunk), c_int, c_int]
_mix_lib.Mix_PlayChannelTimed.restype = c_int
if hasattr(_mix_lib, 'Mix_PlayMusic'):
_mix_lib.Mix_PlayMusic.argtypes = [c_void_p, c_int]
_mix_lib.Mix_PlayMusic.restype = c_int
if hasattr(_mix_lib, 'Mix_Pause'):
_mix_lib.Mix_Pause.argtypes = [c_int]
_mix_lib.Mix_Pause.restype = None
if hasattr(_mix_lib, 'Mix_PauseMusic'):
_mix_lib.Mix_PauseMusic.argtypes = []
_mix_lib.Mix_PauseMusic.restype = None
if hasattr(_mix_lib, 'Mix_Resume'):
_mix_lib.Mix_Resume.argtypes = [c_int]
_mix_lib.Mix_Resume.restype = None
if hasattr(_mix_lib, 'Mix_ResumeMusic'):
_mix_lib.Mix_ResumeMusic.argtypes = []
_mix_lib.Mix_ResumeMusic.restype = None
if hasattr(_mix_lib, 'Mix_HaltChannel'):
_mix_lib.Mix_HaltChannel.argtypes = [c_int]
_mix_lib.Mix_HaltChannel.restype = c_int
if hasattr(_mix_lib, 'Mix_HaltMusic'):
_mix_lib.Mix_HaltMusic.argtypes = []
_mix_lib.Mix_HaltMusic.restype = c_int
if hasattr(_mix_lib, 'Mix_SetMusicPosition'):
_mix_lib.Mix_SetMusicPosition.argtypes = [c_double]
_mix_lib.Mix_SetMusicPosition.restype = c_int
if hasattr(_mix_lib, 'Mix_MusicDuration'):
_mix_lib.Mix_MusicDuration.argtypes = [c_void_p]
_mix_lib.Mix_MusicDuration.restype = c_float
if hasattr(_mix_lib, 'Mix_Volume'):
_mix_lib.Mix_Volume.argtypes = [c_int, c_int]
_mix_lib.Mix_Volume.restype = c_int
if hasattr(_mix_lib, 'Mix_VolumeMusic'):
_mix_lib.Mix_VolumeMusic.argtypes = [c_int]
_mix_lib.Mix_VolumeMusic.restype = c_int
if hasattr(_mix_lib, 'Mix_AllocateChannels'):
_mix_lib.Mix_AllocateChannels.argtypes = [c_int]
_mix_lib.Mix_AllocateChannels.restype = c_int
if hasattr(_mix_lib, 'Mix_GetMusicType'):
_mix_lib.Mix_GetMusicType.argtypes = [c_void_p]
_mix_lib.Mix_GetMusicType.restype = c_int
if hasattr(_mix_lib, 'Mix_FadingMusic'):
_mix_lib.Mix_FadingMusic.argtypes = []
_mix_lib.Mix_FadingMusic.restype = c_int
if hasattr(_mix_lib, 'Mix_FadeInMusic'):
_mix_lib.Mix_FadeInMusic.argtypes = [c_void_p, c_int, c_int]
_mix_lib.Mix_FadeInMusic.restype = c_int
if hasattr(_mix_lib, 'Mix_FadeOutMusic'):
_mix_lib.Mix_FadeOutMusic.argtypes = [c_int]
_mix_lib.Mix_FadeOutMusic.restype = c_int
if hasattr(_mix_lib, 'Mix_FadeInChannel'):
_mix_lib.Mix_FadeInChannel.argtypes = [c_int, POINTER(Mix_Chunk), c_int, c_int]
_mix_lib.Mix_FadeInChannel.restype = c_int
elif hasattr(_mix_lib, 'Mix_FadeInChannelTimed'):
_mix_lib.Mix_FadeInChannelTimed.argtypes = [c_int, POINTER(Mix_Chunk), c_int, c_int, c_int]
_mix_lib.Mix_FadeInChannelTimed.restype = c_int
if hasattr(_mix_lib, 'Mix_FadeOutChannel'):
_mix_lib.Mix_FadeOutChannel.argtypes = [c_int, c_int]
_mix_lib.Mix_FadeOutChannel.restype = c_int
if hasattr(_mix_lib, 'Mix_Playing'):
_mix_lib.Mix_Playing.argtypes = [c_int]
_mix_lib.Mix_Playing.restype = c_int
if hasattr(_mix_lib, 'Mix_PlayingMusic'):
_mix_lib.Mix_PlayingMusic.argtypes = []
_mix_lib.Mix_PlayingMusic.restype = c_int
if hasattr(_mix_lib, 'Mix_Paused'):
_mix_lib.Mix_Paused.argtypes = [c_int]
_mix_lib.Mix_Paused.restype = c_int
if hasattr(_mix_lib, 'Mix_PausedMusic'):
_mix_lib.Mix_PausedMusic.argtypes = []
_mix_lib.Mix_PausedMusic.restype = c_int
if hasattr(_mix_lib, 'Mix_SetPanning'):
_mix_lib.Mix_SetPanning.argtypes = [c_int, c_uint8, c_uint8]
_mix_lib.Mix_SetPanning.restype = c_int
if hasattr(_mix_lib, 'Mix_SetDistance'):
_mix_lib.Mix_SetDistance.argtypes = [c_int, c_uint8]
_mix_lib.Mix_SetDistance.restype = c_int
if hasattr(_mix_lib, 'Mix_SetPosition'):
_mix_lib.Mix_SetPosition.argtypes = [c_int, c_uint16, c_uint8]
_mix_lib.Mix_SetPosition.restype = c_int
if hasattr(_mix_lib, 'Mix_SetReverseStereo'):
_mix_lib.Mix_SetReverseStereo.argtypes = [c_int, c_int]
_mix_lib.Mix_SetReverseStereo.restype = c_int
# ============================================================
# Initialize: Load SDL2 and set up prototypes
# ============================================================
# Load SDL2 libraries
_sdl_lib, _mix_lib = import_sdl2()
# Set up function prototypes
_setup_prototypes()