mirror of
https://github.com/MCV-Software/TWBlue.git
synced 2024-11-23 03:38:08 -06:00
191 lines
5.6 KiB
Python
191 lines
5.6 KiB
Python
from __future__ import division
|
|
from __future__ import absolute_import
|
|
from future.builtins import object
|
|
from functools import partial
|
|
import platform
|
|
from ctypes import c_char_p, c_float, pointer, string_at
|
|
from sound_lib.external.pybass import *
|
|
from . import config
|
|
from .main import bass_call, bass_call_0, EAX_ENVIRONMENTS, update_3d_system
|
|
|
|
_getter = lambda func, key, obj: func(obj)[key]
|
|
_setter = lambda func, kwarg, obj, val: func(obj, **{kwarg: val})
|
|
|
|
class Output (object):
|
|
|
|
def __init__(self, device=-1, frequency=44100, flags=0, window=0, clsid=None):
|
|
try:
|
|
self.use_default_device()
|
|
except:
|
|
pass
|
|
self._device = device
|
|
self.frequency = frequency
|
|
self.flags = flags
|
|
self.window = window
|
|
self.clsid = clsid
|
|
self.init_device(device=device, frequency=frequency, flags=flags, window=window, clsid=clsid)
|
|
self.config = config.BassConfig()
|
|
self.proxy = None
|
|
|
|
def init_device(self, device=None, frequency=None, flags=None, window=None, clsid=None):
|
|
if device is None:
|
|
device = self._device
|
|
self._device = device
|
|
if frequency is None:
|
|
frequency = self.frequency
|
|
self.frequency = frequency
|
|
if flags is None:
|
|
flags = self.flags
|
|
self.flags = flags
|
|
if window is None:
|
|
window = self.window
|
|
self.window = window
|
|
if clsid is None:
|
|
clsid = self.clsid
|
|
self.clsid = clsid
|
|
if platform.system() == 'Linux' and device == -1: #Bass wants default device set to 1 on linux
|
|
device = 1
|
|
bass_call(BASS_Init, device, frequency, flags, window, clsid)
|
|
|
|
def start(self):
|
|
return bass_call(BASS_Start)
|
|
|
|
def pause(self):
|
|
return bass_call(BASS_Pause)
|
|
|
|
def stop(self):
|
|
return bass_call(BASS_Stop)
|
|
|
|
def get_device(self):
|
|
return bass_call_0(BASS_GetDevice)
|
|
|
|
def set_device(self, device):
|
|
if device == self._device:
|
|
return
|
|
self.free()
|
|
self.init_device(device=device)
|
|
return bass_call(BASS_SetDevice, device)
|
|
|
|
device = property(fget=get_device, fset=set_device)
|
|
|
|
def get_volume (self):
|
|
volume = BASS_GetConfig(BASS_CONFIG_GVOL_STREAM)
|
|
if volume:
|
|
volume = volume / 100.0
|
|
return volume
|
|
|
|
def set_volume (self, volume):
|
|
#Pass in a float 0.0 to 100.0 and watch the volume magically change
|
|
return bass_call(BASS_SetConfig, BASS_CONFIG_GVOL_STREAM, int(round(volume*100, 2)))
|
|
|
|
volume = property(get_volume, set_volume)
|
|
|
|
@staticmethod
|
|
def free():
|
|
return bass_call(BASS_Free)
|
|
|
|
def get_proxy(self):
|
|
ptr = bass_call(BASS_GetConfigPtr, BASS_CONFIG_NET_PROXY)
|
|
return string_at(ptr)
|
|
|
|
def set_proxy(self, proxy):
|
|
self.proxy = c_char_p(proxy)
|
|
return bass_call(BASS_SetConfigPtr, BASS_CONFIG_NET_PROXY, self.proxy)
|
|
|
|
def use_default_device(self, use=True):
|
|
return bass_call(BASS_SetConfig, BASS_CONFIG_DEV_DEFAULT, use)
|
|
|
|
@staticmethod
|
|
def get_device_names():
|
|
"""Convenience method that returns a list of device names that are considered
|
|
valid by bass.
|
|
|
|
Parameters: none.
|
|
returns: list of devices, 0-indexed.
|
|
"""
|
|
result = [] # empty list to start.
|
|
info = BASS_DEVICEINFO()
|
|
count = 1
|
|
while BASS_GetDeviceInfo(count, ctypes.byref(info)):
|
|
if info.flags & BASS_DEVICE_ENABLED:
|
|
retrieved = info.name
|
|
if platform.system() == 'Windows':
|
|
retrieved = retrieved.decode('mbcs')
|
|
retrieved = retrieved.replace('(', '').replace(')', '').strip()
|
|
result.append(retrieved)
|
|
count += 1
|
|
return result
|
|
|
|
def find_device_by_name(self, name):
|
|
return self.get_device_names().index(name) + 1
|
|
|
|
def find_default_device(self):
|
|
try:
|
|
return self.get_device_names().index('Default')+1
|
|
except:
|
|
return -1
|
|
|
|
def find_user_provided_device(self, device_name):
|
|
try:
|
|
return self.find_device_by_name(device_name)
|
|
except ValueError:
|
|
return self.find_default_device()
|
|
|
|
class ThreeDOutput(Output):
|
|
|
|
def __init__(self, flags=BASS_DEVICE_3D, *args, **kwargs):
|
|
super(ThreeDOutput, self).__init__(flags=flags, *args, **kwargs)
|
|
|
|
def get_3d_factors(self):
|
|
res = {
|
|
'distance_factor': c_float(),
|
|
'rolloff': c_float(),
|
|
'doppler_factor': c_float()
|
|
}
|
|
bass_call(BASS_Get3DFactors, pointer(res['distance_factor']), pointer(res['rolloff']), pointer(res['doppler_factor']))
|
|
return {k: res[k].value for k in res}
|
|
|
|
@update_3d_system
|
|
def set_3d_factors(self, distance_factor=-1, rolloff=-1, doppler_factor=-1):
|
|
conversions = {
|
|
'meters': 1.0,
|
|
'yards': 0.9144,
|
|
'feet': 0.3048
|
|
}
|
|
if distance_factor in conversions:
|
|
distance_factor = conversions[distance_factor]
|
|
return bass_call(BASS_Set3DFactors, distance_factor, rolloff, doppler_factor)
|
|
|
|
distance_factor = property(fget=partial(_getter, get_3d_factors, 'distance_factor'), fset=partial(_setter, set_3d_factors, 'distance_factor'))
|
|
|
|
rolloff = property(fget=partial(_getter, get_3d_factors, 'rolloff'), fset=partial(_setter, set_3d_factors, 'rolloff'))
|
|
|
|
doppler_factor = property(fget=partial(_getter, get_3d_factors, 'doppler_factor'), fset=partial(_setter, set_3d_factors, 'doppler_factor'))
|
|
|
|
def set_eax_parameters(self, environment=None, volume=None, decay=None, damp=None):
|
|
def convert_arg(arg):
|
|
if arg is None:
|
|
arg = -1
|
|
return arg
|
|
environment = convert_arg(environment)
|
|
if isinstance(environment, str) and environment in EAX_ENVIRONMENTS:
|
|
environment = EAX_ENVIRONMENTS[environment]
|
|
volume = convert_arg(volume)
|
|
decay = convert_arg(decay)
|
|
damp = convert_arg(damp)
|
|
bass_call(BASS_SetEAXParameters, environment, volume, decay, damp)
|
|
|
|
def get_3d_algorithm(self):
|
|
return BASS_GetConfig(BASS_CONFIG_3DALGORITHM)
|
|
|
|
def set_3d_algorithm(self, algo):
|
|
replacements = {
|
|
'default': BASS_3DALG_DEFAULT,
|
|
'off': BASS_3DALG_OFF,
|
|
'full': BASS_3DALG_FULL,
|
|
'light': BASS_3DALG_LIGHT,
|
|
}
|
|
if algo in replacements:
|
|
algo = replacements[algo]
|
|
return BASS_SetConfig(BASS_CONFIG_3DALGORITHM, algo)
|