pyglet bump
This commit is contained in:
parent
4fa8619f69
commit
9dcf407ff7
@ -19,6 +19,9 @@ kCFStringEncodingUTF8 = 0x08000100
|
||||
|
||||
CFAllocatorRef = c_void_p
|
||||
CFStringEncoding = c_uint32
|
||||
CFURLRef = c_void_p
|
||||
CFStringRef = c_void_p
|
||||
CFURLPathStyle = c_int
|
||||
|
||||
cf.CFStringCreateWithCString.restype = c_void_p
|
||||
cf.CFStringCreateWithCString.argtypes = [CFAllocatorRef, c_char_p, CFStringEncoding]
|
||||
@ -97,6 +100,10 @@ cf.CFNumberGetTypeID.argtypes = []
|
||||
cf.CFGetTypeID.restype = CFTypeID
|
||||
cf.CFGetTypeID.argtypes = [c_void_p]
|
||||
|
||||
cf.CFURLCreateWithFileSystemPath.restype = CFURLRef
|
||||
cf.CFURLCreateWithFileSystemPath.argtypes = [CFAllocatorRef, CFStringRef, CFURLPathStyle, c_bool]
|
||||
|
||||
|
||||
# CFNumber.h
|
||||
kCFNumberSInt8Type = 1
|
||||
kCFNumberSInt16Type = 2
|
||||
|
172
libs/pyglet/libs/darwin/coreaudio.py
Normal file
172
libs/pyglet/libs/darwin/coreaudio.py
Normal file
@ -0,0 +1,172 @@
|
||||
import ctypes
|
||||
from ctypes import c_void_p, c_int, c_bool, Structure, c_uint32, util, cdll, c_uint, c_double, POINTER, c_int64
|
||||
|
||||
from pyglet.libs.darwin import CFURLRef
|
||||
|
||||
lib = util.find_library('CoreAudio')
|
||||
|
||||
if lib is None:
|
||||
lib = '/System/Library/Frameworks/CoreAudio.framework/CoreAudio'
|
||||
|
||||
ca = cdll.LoadLibrary(lib)
|
||||
|
||||
|
||||
class AudioStreamPacketDescription(Structure):
|
||||
_fields_ = [
|
||||
('mStartOffset', c_int64),
|
||||
('mVariableFramesInPacket', c_uint32),
|
||||
('mDataByteSize', c_uint32)
|
||||
]
|
||||
|
||||
|
||||
class AudioStreamBasicDescription(Structure):
|
||||
_fields_ = [
|
||||
('mSampleRate', c_double),
|
||||
('mFormatID', c_uint32),
|
||||
('mFormatFlags', c_uint32),
|
||||
('mBytesPerPacket', c_uint32),
|
||||
('mFramesPerPacket', c_uint32),
|
||||
('mBytesPerFrame', c_uint32),
|
||||
('mChannelsPerFrame', c_uint32),
|
||||
('mBitsPerChannel', c_uint32),
|
||||
('mReserved', c_uint32)
|
||||
]
|
||||
|
||||
def __repr__(self):
|
||||
return f"AudioStreamBasicDescription(sample_rate={self.mSampleRate}, channels={self.mChannelsPerFrame}, " \
|
||||
f"fmt={self.mFormatID}, bytes_per_packet={self.mBytesPerPacket}, bits={self.mBitsPerChannel}, " \
|
||||
f"frames_per_packet={self.mFramesPerPacket}, bytes_per_frame={self.mBytesPerFrame})"
|
||||
|
||||
|
||||
class AudioBuffer(Structure):
|
||||
_fields_ = [
|
||||
("mNumberChannels", c_uint),
|
||||
("mDataByteSize", c_uint),
|
||||
("mData", c_void_p),
|
||||
]
|
||||
|
||||
|
||||
class AudioBufferList(Structure):
|
||||
_fields_ = [
|
||||
("mNumberBuffers", c_uint),
|
||||
("mBuffers", AudioBuffer * 1),
|
||||
]
|
||||
|
||||
|
||||
kCFURLPOSIXPathStyle = 0
|
||||
ExtAudioFilePropertyID = c_uint32
|
||||
OSStatus = c_int
|
||||
|
||||
ExtAudioFileRef = c_void_p
|
||||
|
||||
ca.ExtAudioFileOpenURL.restype = c_int
|
||||
ca.ExtAudioFileOpenURL.argtypes = [CFURLRef, ExtAudioFileRef]
|
||||
|
||||
ca.ExtAudioFileGetProperty.restype = c_int
|
||||
ca.ExtAudioFileGetProperty.argtypes = [ExtAudioFileRef, ExtAudioFilePropertyID, POINTER(c_uint32), c_void_p]
|
||||
|
||||
ca.ExtAudioFileSetProperty.restype = c_int
|
||||
ca.ExtAudioFileSetProperty.argtypes = [ExtAudioFileRef, ExtAudioFilePropertyID, c_uint32, c_void_p]
|
||||
|
||||
ca.ExtAudioFileOpenURL.restype = OSStatus
|
||||
ca.ExtAudioFileOpenURL.argtypes = [CFURLRef, ExtAudioFileRef]
|
||||
|
||||
AudioFileTypeID = c_uint32
|
||||
AudioFileID = c_void_p
|
||||
|
||||
AudioFile_ReadProc = ctypes.CFUNCTYPE(c_int, c_void_p, ctypes.c_int64, c_uint32, c_void_p, POINTER(c_uint32))
|
||||
AudioFile_GetSizeProc = ctypes.CFUNCTYPE(ctypes.c_int64, c_void_p)
|
||||
|
||||
ca.AudioFileOpenWithCallbacks.restype = OSStatus
|
||||
ca.AudioFileOpenWithCallbacks.argtypes = [c_void_p, AudioFile_ReadProc, c_void_p, AudioFile_GetSizeProc, c_void_p,
|
||||
AudioFileTypeID, POINTER(AudioFileID)]
|
||||
|
||||
ca.ExtAudioFileWrapAudioFileID.restype = OSStatus
|
||||
ca.ExtAudioFileWrapAudioFileID.argtypes = [AudioFileID, c_bool, POINTER(ExtAudioFileRef)]
|
||||
|
||||
ca.ExtAudioFileRead.restype = OSStatus
|
||||
ca.ExtAudioFileRead.argtypes = [ExtAudioFileRef, POINTER(c_uint32), POINTER(AudioBufferList)]
|
||||
|
||||
ca.ExtAudioFileSeek.restype = OSStatus
|
||||
ca.ExtAudioFileSeek.argtypes = [ExtAudioFileRef, c_int64]
|
||||
|
||||
ca.ExtAudioFileDispose.restype = OSStatus
|
||||
ca.ExtAudioFileDispose.argtypes = [ExtAudioFileRef]
|
||||
|
||||
ca.AudioFileClose.restype = OSStatus
|
||||
ca.AudioFileClose.argtypes = [AudioFileID]
|
||||
|
||||
kCFAllocatorDefault = None
|
||||
|
||||
|
||||
def c_literal(literal):
|
||||
"""Example 'xyz' -> 7895418.
|
||||
Used for some CoreAudio constants."""
|
||||
num = 0
|
||||
for idx, char in enumerate(literal):
|
||||
num |= ord(char) << (len(literal) - idx - 1) * 8
|
||||
return num
|
||||
|
||||
|
||||
kAudioFilePropertyMagicCookieData = c_literal('mgic')
|
||||
kExtAudioFileProperty_FileDataFormat = c_literal('ffmt')
|
||||
kExtAudioFileProperty_ClientDataFormat = c_literal('cfmt')
|
||||
kExtAudioFileProperty_FileLengthFrames = c_literal('#frm')
|
||||
kAudioFormatLinearPCM = c_literal('lpcm')
|
||||
|
||||
kAudioFormatFlagIsFloat = 1 << 0
|
||||
kAudioFormatFlagIsBigEndian = 1 << 1
|
||||
kAudioFormatFlagIsSignedInteger = 1 << 2
|
||||
kAudioFormatFlagIsPacked = 1 << 3
|
||||
kAudioFormatFlagsNativeEndian = 0
|
||||
kAudioFormatFlagsCanonical = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked
|
||||
kAudioQueueProperty_MagicCookie = c_literal('aqmc')
|
||||
|
||||
# ERRORS:
|
||||
kAudio_UnimplementedError = -4
|
||||
kAudio_FileNotFoundError = -43
|
||||
kAudio_ParamError = -50
|
||||
kAudio_MemFullError = -108
|
||||
|
||||
kAudioFileUnspecifiedError = c_literal('wht?') # 0x7768743F, 2003334207
|
||||
kAudioFileUnsupportedFileTypeError = c_literal('typ?') # 0x7479703F, 1954115647
|
||||
kAudioFileUnsupportedDataFormatError = c_literal('fmt?') # 0x666D743F, 1718449215
|
||||
kAudioFileUnsupportedPropertyError = c_literal('pty?') # 0x7074793F, 1886681407
|
||||
kAudioFileBadPropertySizeError = c_literal('!siz') # 0x2173697A, 561211770
|
||||
kAudioFilePermissionsError = c_literal('prm?') # 0x70726D3F, 1886547263
|
||||
kAudioFileNotOptimizedError = c_literal('optm') # 0x6F70746D, 1869640813
|
||||
# file format specific error codes
|
||||
kAudioFileInvalidChunkError = c_literal('chk?') # 0x63686B3F, 1667787583
|
||||
kAudioFileDoesNotAllow64BitDataSizeError = c_literal('off?') # 0x6F66663F, 1868981823
|
||||
kAudioFileInvalidPacketOffsetError = c_literal('pck?') # 0x70636B3F, 1885563711
|
||||
kAudioFileInvalidFileError = c_literal('dta?') # 0x6474613F, 1685348671
|
||||
kAudioFileOperationNotSupportedError = c_literal('op?') # 0x6F703F3F
|
||||
# general file error codes
|
||||
kAudioFileNotOpenError = -38
|
||||
kAudioFileEndOfFileError = -39
|
||||
kAudioFilePositionError = -40
|
||||
kAudioFileFileNotFoundError = -43
|
||||
|
||||
err_str_db = {
|
||||
kAudioFileUnspecifiedError: "An unspecified error has occurred.",
|
||||
kAudioFileUnsupportedFileTypeError: "The file type is not supported.",
|
||||
kAudioFileUnsupportedDataFormatError: "The data format is not supported by this file type.",
|
||||
kAudioFileUnsupportedPropertyError: "The property is not supported.",
|
||||
kAudioFileBadPropertySizeError: "The size of the property data was not correct.",
|
||||
kAudioFilePermissionsError: "The operation violated the file permissions.",
|
||||
kAudioFileNotOptimizedError: "The chunks following the audio data chunk are preventing the extension of the audio data chunk. To write more data, you must optimize the file.",
|
||||
kAudioFileInvalidChunkError: "Either the chunk does not exist in the file or it is not supported by the file.",
|
||||
kAudioFileDoesNotAllow64BitDataSizeError: "The file offset was too large for the file type. The AIFF and WAVE file format types have 32-bit file size limits.",
|
||||
kAudioFileInvalidPacketOffsetError: "A packet offset was past the end of the file, or not at the end of the file when a VBR format was written, or a corrupt packet size was read when the packet table was built.",
|
||||
kAudioFileInvalidFileError: "The file is malformed, or otherwise not a valid instance of an audio file of its type.",
|
||||
kAudioFileOperationNotSupportedError: "The operation cannot be performed.",
|
||||
kAudioFileNotOpenError: "The file is closed.",
|
||||
kAudioFileEndOfFileError: "End of file.",
|
||||
kAudioFilePositionError: "Invalid file position.",
|
||||
kAudioFileFileNotFoundError: "File not found.",
|
||||
}
|
||||
|
||||
|
||||
def err_check(err):
|
||||
if err != 0:
|
||||
raise Exception(err, err_str_db.get(err, "Unknown Error"))
|
182
libs/pyglet/media/codecs/coreaudio.py
Normal file
182
libs/pyglet/media/codecs/coreaudio.py
Normal file
@ -0,0 +1,182 @@
|
||||
from ctypes import memmove, byref, c_uint32, sizeof, cast, c_void_p, create_string_buffer, POINTER, c_char, \
|
||||
c_long
|
||||
|
||||
from pyglet.libs.darwin import cf, CFSTR
|
||||
from pyglet.libs.darwin.coreaudio import kCFURLPOSIXPathStyle, AudioStreamBasicDescription, ca, ExtAudioFileRef, \
|
||||
kExtAudioFileProperty_FileDataFormat, kAudioFormatLinearPCM, kAudioFormatFlagIsSignedInteger, \
|
||||
kAudioFormatFlagIsPacked, kExtAudioFileProperty_ClientDataFormat, AudioFile_ReadProc, \
|
||||
AudioFile_GetSizeProc, AudioBufferList, kExtAudioFileProperty_FileLengthFrames, AudioFileID, err_check
|
||||
from pyglet.media import StreamingSource, StaticSource
|
||||
from pyglet.media.codecs import AudioFormat, MediaDecoder, AudioData
|
||||
|
||||
|
||||
class MemoryFileObject:
|
||||
|
||||
def __init__(self, file):
|
||||
self.file = file
|
||||
|
||||
if not getattr(self.file, 'seek', None) or not getattr(self.file, 'tell', None):
|
||||
raise Exception("File object does not support seeking.")
|
||||
|
||||
# Seek to end of file to get the filesize.
|
||||
self.file.seek(0, 2)
|
||||
self.file_size = self.file.tell()
|
||||
self.file.seek(0) # Put cursor back at the beginning.
|
||||
self.data = []
|
||||
|
||||
def read_data_cb(ref, offset, requested_length, buffer, actual_count):
|
||||
self.file.seek(offset)
|
||||
data = self.file.read(requested_length)
|
||||
data_size = len(data)
|
||||
memmove(buffer, data, data_size)
|
||||
actual_count.contents.value = data_size # Actual read.
|
||||
return 0
|
||||
|
||||
def getsize_cb(ref):
|
||||
return self.file_size
|
||||
|
||||
self.getsize_func = AudioFile_GetSizeProc(getsize_cb)
|
||||
self.read_func = AudioFile_ReadProc(read_data_cb)
|
||||
|
||||
|
||||
class CoreAudioSource(StreamingSource):
|
||||
def __init__(self, filename, file=None):
|
||||
self._bl = None
|
||||
self._file = file
|
||||
self._deleted = False
|
||||
self._file_obj = None
|
||||
self._audfile = None
|
||||
self._audref = None
|
||||
|
||||
audref = ExtAudioFileRef()
|
||||
if file is None:
|
||||
fn_str = CFSTR(filename)
|
||||
url_ref = cf.CFURLCreateWithFileSystemPath(None, fn_str, kCFURLPOSIXPathStyle, False)
|
||||
|
||||
err_check(ca.ExtAudioFileOpenURL(url_ref, byref(audref)))
|
||||
else:
|
||||
self.file_obj = MemoryFileObject(file)
|
||||
|
||||
self._audfile = AudioFileID()
|
||||
|
||||
err_check(ca.AudioFileOpenWithCallbacks(
|
||||
None, self.file_obj.read_func, None, self.file_obj.getsize_func, None,
|
||||
0,
|
||||
byref(self._audfile))
|
||||
)
|
||||
|
||||
err_check(ca.ExtAudioFileWrapAudioFileID(self._audfile, False, byref(audref)))
|
||||
|
||||
self._audref = audref
|
||||
|
||||
format_info = AudioStreamBasicDescription()
|
||||
size = c_uint32(sizeof(format_info))
|
||||
err_check(ca.ExtAudioFileGetProperty(self._audref,
|
||||
kExtAudioFileProperty_FileDataFormat,
|
||||
byref(size),
|
||||
byref(format_info)))
|
||||
|
||||
self.convert_desc = self.convert_format(format_info)
|
||||
|
||||
err_check(ca.ExtAudioFileSetProperty(
|
||||
self._audref,
|
||||
kExtAudioFileProperty_ClientDataFormat,
|
||||
sizeof(self.convert_desc),
|
||||
byref(self.convert_desc)
|
||||
))
|
||||
|
||||
length = c_long()
|
||||
size = c_uint32(sizeof(format_info))
|
||||
# File length.
|
||||
err_check(ca.ExtAudioFileGetProperty(
|
||||
self._audref,
|
||||
kExtAudioFileProperty_FileLengthFrames,
|
||||
byref(size),
|
||||
byref(length)
|
||||
))
|
||||
|
||||
self.audio_format = AudioFormat(channels=self.convert_desc.mChannelsPerFrame,
|
||||
sample_size=self.convert_desc.mBitsPerChannel,
|
||||
sample_rate=int(self.convert_desc.mSampleRate))
|
||||
|
||||
self._num_frames = length.value
|
||||
self._bytes_per_frame = self.convert_desc.mBytesPerFrame
|
||||
self._duration = self._num_frames / self.convert_desc.mSampleRate
|
||||
self._duration_per_frame = self._duration / self._num_frames
|
||||
|
||||
@staticmethod
|
||||
def convert_format(original_desc, bitdepth=16):
|
||||
adesc = AudioStreamBasicDescription()
|
||||
adesc.mSampleRate = original_desc.mSampleRate
|
||||
adesc.mFormatID = kAudioFormatLinearPCM
|
||||
adesc.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked
|
||||
adesc.mChannelsPerFrame = original_desc.mChannelsPerFrame
|
||||
adesc.mBitsPerChannel = bitdepth
|
||||
adesc.mBytesPerPacket = original_desc.mChannelsPerFrame * adesc.mBitsPerChannel // 8
|
||||
adesc.mFramesPerPacket = 1
|
||||
adesc.mBytesPerFrame = adesc.mBytesPerPacket
|
||||
return adesc
|
||||
|
||||
def __del__(self):
|
||||
if self._file:
|
||||
self._file.close()
|
||||
self._file = None
|
||||
|
||||
if self._audfile:
|
||||
err_check(ca.AudioFileClose(self._audfile))
|
||||
self._audfile = None
|
||||
|
||||
if self._audref:
|
||||
err_check(ca.ExtAudioFileDispose(self._audref))
|
||||
self._audref = None
|
||||
|
||||
def get_audio_data(self, num_bytes, compensation_time=0.0):
|
||||
num_frames = c_uint32(num_bytes // self.convert_desc.mBytesPerFrame)
|
||||
|
||||
if not self._bl:
|
||||
buffer = create_string_buffer(num_bytes)
|
||||
self._bl = AudioBufferList()
|
||||
self._bl.mNumberBuffers = 1
|
||||
self._bl.mBuffers[0].mNumberChannels = self.convert_desc.mChannelsPerFrame
|
||||
self._bl.mBuffers[0].mDataByteSize = num_bytes
|
||||
self._bl.mBuffers[0].mData = cast(buffer, c_void_p)
|
||||
|
||||
while True:
|
||||
ca.ExtAudioFileRead(self._audref, byref(num_frames), byref(self._bl))
|
||||
|
||||
size = self._bl.mBuffers[0].mDataByteSize
|
||||
if not size:
|
||||
break
|
||||
|
||||
data = cast(self._bl.mBuffers[0].mData, POINTER(c_char))
|
||||
slice = data[:size]
|
||||
return AudioData(slice, size, 0.0, 0.0, [])
|
||||
|
||||
def seek(self, timestamp):
|
||||
timestamp = max(0.0, min(timestamp, self._duration))
|
||||
position = int(timestamp / self._duration_per_frame)
|
||||
ca.ExtAudioFileSeek(self._audref, position)
|
||||
|
||||
|
||||
#########################################
|
||||
# Decoder class:
|
||||
#########################################
|
||||
|
||||
class CoreAudioDecoder(MediaDecoder):
|
||||
|
||||
def get_file_extensions(self):
|
||||
return '.aac', '.ac3', '.aif', '.aiff', '.aifc', '.caf', '.mp3', '.mp4', '.m4a', '.snd', '.au', '.sd2', '.wav'
|
||||
|
||||
def decode(self, filename, file, streaming=True):
|
||||
if streaming:
|
||||
return CoreAudioSource(filename, file)
|
||||
else:
|
||||
return StaticSource(CoreAudioSource(filename, file))
|
||||
|
||||
|
||||
def get_decoders():
|
||||
return [CoreAudioDecoder()]
|
||||
|
||||
|
||||
def get_encoders():
|
||||
return []
|
@ -13,7 +13,7 @@ _debug = debug_print('debug_media')
|
||||
avutil = pyglet.lib.load_library(
|
||||
'avutil',
|
||||
win32=('avutil-57', 'avutil-56'),
|
||||
darwin=('avutil.57', 'avutil-56')
|
||||
darwin=('avutil.57', 'avutil.56')
|
||||
)
|
||||
|
||||
avutil.avutil_version.restype = c_int
|
||||
|
@ -34,15 +34,17 @@ def get_audio_driver():
|
||||
_audio_driver = pulse.create_audio_driver()
|
||||
break
|
||||
elif driver_name == 'xaudio2':
|
||||
from pyglet.libs.win32.constants import WINDOWS_8_OR_GREATER
|
||||
if WINDOWS_8_OR_GREATER:
|
||||
from . import xaudio2
|
||||
_audio_driver = xaudio2.create_audio_driver()
|
||||
break
|
||||
if pyglet.compat_platform in ('win32', 'cygwin'):
|
||||
from pyglet.libs.win32.constants import WINDOWS_8_OR_GREATER
|
||||
if WINDOWS_8_OR_GREATER:
|
||||
from . import xaudio2
|
||||
_audio_driver = xaudio2.create_audio_driver()
|
||||
break
|
||||
elif driver_name == 'directsound':
|
||||
from . import directsound
|
||||
_audio_driver = directsound.create_audio_driver()
|
||||
break
|
||||
if pyglet.compat_platform in ('win32', 'cygwin'):
|
||||
from . import directsound
|
||||
_audio_driver = directsound.create_audio_driver()
|
||||
break
|
||||
elif driver_name == 'openal':
|
||||
from . import openal
|
||||
_audio_driver = openal.create_audio_driver()
|
||||
|
Loading…
Reference in New Issue
Block a user