# 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()