Make effects properties more intuitive (fix GH-85)

Additionally run flake8 within pytest by default for better CI experience.
This commit is contained in:
Nguyễn Gia Phong 2020-04-25 21:33:17 +07:00
parent 88c5b0b57a
commit 9de664a750
6 changed files with 488 additions and 211 deletions

View File

@ -23,7 +23,8 @@ from sys import stderr
from time import sleep
from typing import Iterable
from palace import reverb_preset_names, decode, Device, Context, Source, Effect
from palace import (reverb_preset_names, decode,
Device, Context, Source, ReverbEffect)
CHUNK_LEN: int = 12000
QUEUE_SIZE: int = 4
@ -48,11 +49,9 @@ def play(files: Iterable[str], device: str, reverb: str) -> None:
"""Load and play files on the given device."""
with Device(device) as dev, Context(dev) as ctx:
print('Opened', dev.name)
with Source() as src, Effect() as fx:
print('Loading reverb preset', reverb)
fx.reverb_preset = reverb
print('Loading reverb preset', reverb)
with Source() as src, ReverbEffect(reverb) as fx:
src.sends[0].effect = fx
for filename in files:
try:
decoder = decode(filename)

View File

@ -84,37 +84,37 @@ cdef extern from 'alure2-typeviews.h' namespace 'alure' nogil:
# Alure main module
cdef extern from 'alure2.h' nogil:
cdef cppclass EFXEAXREVERBPROPERTIES:
float flDensity
float flDiffusion
float flGain
float flGainHF
float flGainLF
float flDecayTime
float flDecayHFRatio
float flDecayLFRatio
float flReflectionsGain
float flReflectionsDelay
float flReflectionsPan[3]
float flLateReverbGain
float flLateReverbDelay
float flLateReverbPan[3]
float flEchoTime
float flEchoDepth
float flModulationTime
float flModulationDepth
float flAirAbsorptionGainHF
float flHFReference
float flLFReference
float flRoomRolloffFactor
int iDecayHFLimit
float density 'flDensity'
float diffusion 'flDiffusion'
float gain 'flGain'
float gain_hf 'flGainHF'
float gain_lf 'flGainLF'
float decay_time 'flDecayTime'
float decay_hf_ratio 'flDecayHFRatio'
float decay_lf_ratio 'flDecayLFRatio'
float reflections_gain 'flReflectionsGain'
float reflections_delay 'flReflectionsDelay'
float reflections_pan 'flReflectionsPan'[3]
float late_reverb_gain 'flLateReverbGain'
float late_reverb_delay 'flLateReverbDelay'
float late_reverb_pan 'flLateReverbPan'[3]
float echo_time 'flEchoTime'
float echo_depth 'flEchoDepth'
float modulation_time 'flModulationTime'
float modulation_depth 'flModulationDepth'
float air_absorption_gain_hf 'flAirAbsorptionGainHF'
float hf_reference 'flHFReference'
float lf_reference 'flLFReference'
float room_rolloff_factor 'flRoomRolloffFactor'
int decay_hf_limit 'iDecayHFLimit'
cdef cppclass EFXCHORUSPROPERTIES:
int iWaveform
int iPhase
float flRate
float flDepth
float flFeedback
float flDelay
int waveform 'iWaveform'
int phase 'iPhase'
float rate 'flRate'
float depth 'flDepth'
float feedback 'flFeedback'
float delay 'flDelay'
cdef extern from 'alure2.h' namespace 'alure' nogil:

View File

@ -76,7 +76,8 @@ __all__ = [
'thread_local', 'current_context', 'use_context',
'cache', 'free', 'decode', 'sample_size', 'sample_length',
'Device', 'Context', 'Listener', 'Buffer', 'Source', 'SourceGroup',
'Effect', 'Decoder', 'BaseDecoder', 'FileIO', 'MessageHandler']
'Effect', 'ReverbEffect', 'ChorusEffect',
'Decoder', 'BaseDecoder', 'FileIO', 'MessageHandler']
from abc import abstractmethod, ABCMeta
from contextlib import contextmanager
@ -1736,6 +1737,61 @@ cdef class Source:
"""Destroy the source, stop playback and release resources."""
self.impl.destroy()
cdef class SendPath:
"""Container of write-only descriptors of a send path signal."""
cdef alure.Source source
cdef unsigned send
def __init__(self, source: Source, send: int) -> None:
self.source = source.impl
self.send = send
@setter
def filter(self, value: Vector3) -> None:
"""Linear gains on the send path signal, clamped to [0, 1].
Parameters
----------
gain : float
Linear gain applying to all frequencies, default to 1.
gain_hf : float
Linear gain applying to high frequencies, default to 1.
gain_lf : float
Linear gain applying to low frequencies, default to 1.
"""
gain, gain_hf, gain_lf = value
self.source.set_send_filter(
self.send, make_filter(gain, gain_hf, gain_lf))
@setter
def effect(self, value: BaseEffect) -> None:
"""Effect applied to the send path signal."""
self.source.set_auxiliary_send(value.slot, self.send)
cdef class AuxiliarySends:
"""Collection of SendPath.
It is recommended that applications access instances of
this class via `Source.sends`. From there, one can get a `SendPath`
by indexing the object with a nonnegative integer less than
the device's `max_auxiliary_sends`.
"""
cdef Source source
def __init__(self, source: Source) -> None:
self.source = source
def __getitem__(self, key: int) -> SendPath:
if not isinstance(key, int):
raise TypeError(
f'integer key expected, got {key.__class__.__name__}')
try:
return SendPath(self.source, key)
except OverflowError:
raise IndexError(f'index out of range: {key}') from None
cdef class SourceGroup:
"""A group of `Source` references.
@ -1881,8 +1937,10 @@ cdef class SourceGroup:
self.impl.destroy()
cdef class Effect:
"""An effect processor.
cdef class BaseEffect:
"""Base effect processor.
Instances of this class has no effect (pun intended).
It takes the output mix of zero or more sources,
applies DSP for the desired effect, then adds to the output mix.
@ -1900,6 +1958,11 @@ cdef class Effect:
------
RuntimeError
If there is neither any context specified nor current.
See Also
--------
ReverbEffect : EAXReverb effect
ChorusEffect : Chorus effect
"""
cdef alure.AuxiliaryEffectSlot slot
cdef alure.Effect impl
@ -1910,37 +1973,37 @@ cdef class Effect:
self.slot = alure_context.create_auxiliary_effect_slot()
self.impl = alure_context.create_effect()
def __enter__(self) -> Effect: return self
def __enter__(self) -> BaseEffect: return self
def __exit__(self, *exc) -> Optional[bool]: self.destroy()
def __lt__(self, other: Any) -> bool:
if not isinstance(other, Effect): return NotImplemented
cdef Effect fx = <Effect> other
if not isinstance(other, BaseEffect): return NotImplemented
cdef BaseEffect fx = <BaseEffect> other
return self.slot < fx.slot and self.impl < fx.impl
def __le__(self, other: Any) -> bool:
if not isinstance(other, Effect): return NotImplemented
cdef Effect fx = <Effect> other
if not isinstance(other, BaseEffect): return NotImplemented
cdef BaseEffect fx = <BaseEffect> other
return self.slot <= fx.slot and self.impl <= fx.impl
def __eq__(self, other: Any) -> bool:
if not isinstance(other, Effect): return NotImplemented
cdef Effect fx = <Effect> other
if not isinstance(other, BaseEffect): return NotImplemented
cdef BaseEffect fx = <BaseEffect> other
return self.slot == fx.slot and self.impl == fx.impl
def __ne__(self, other: Any) -> bool:
if not isinstance(other, Effect): return NotImplemented
cdef Effect fx = <Effect> other
if not isinstance(other, BaseEffect): return NotImplemented
cdef BaseEffect fx = <BaseEffect> other
return self.slot != fx.slot and self.impl != fx.impl
def __gt__(self, other: Any) -> bool:
if not isinstance(other, Effect): return NotImplemented
cdef Effect fx = <Effect> other
if not isinstance(other, BaseEffect): return NotImplemented
cdef BaseEffect fx = <BaseEffect> other
return self.slot > fx.slot and self.impl > fx.impl
def __ge__(self, other: Any) -> bool:
if not isinstance(other, Effect): return NotImplemented
cdef Effect fx = <Effect> other
if not isinstance(other, BaseEffect): return NotImplemented
cdef BaseEffect fx = <BaseEffect> other
return self.slot >= fx.slot and self.impl >= fx.impl
def __bool__(self) -> bool:
@ -1951,14 +2014,6 @@ cdef class Effect:
"""Gain of the effect slot."""
self.slot.set_gain(value)
@setter
def send_auto(self, value: bool) -> None:
"""Whether to automatically adjust send slot gains.
This only has effect on reverb effects. Default is `True`.
"""
self.slot.set_send_auto(value)
@getter
def source_sends(self) -> List[Tuple[Source, int]]:
"""List of sources using this effect and their pairing sends."""
@ -1978,83 +2033,6 @@ cdef class Effect:
"""
return self.slot.get_use_count()
@setter
def reverb_preset(self, value: str) -> None:
"""Pre-defined reverb effect.
Raises
------
ValueError
If set to a preset cannot be found in `reverb_preset_names`.
"""
try:
self.impl.set_reverb_properties(REVERB_PRESETS.at(value))
except IndexError:
raise ValueError(f'invalid preset name: {value}') from None
else:
self.slot.apply_effect(self.impl)
@setter
def reverb_properties(self, value: dict) -> None:
"""The effect with the specified reverb properties.
It will automatically downgrade to the Standard Reverb effect
if EAXReverb effect is not supported.
See Also
--------
reverb_preset : Pre-defined reverb effect.
"""
cdef alure.EFXEAXREVERBPROPERTIES properties
properties.flDensity = value['density']
properties.flDiffusion = value['diffusion']
properties.flGain = value['gain']
properties.flGainHF = value['gain_hf']
properties.flGainLF = value['gain_lf']
properties.flDecayTime = value['decay_time']
properties.flDecayHFRatio = value['decay_hf_ratio']
properties.flDecayLFRatio = value['decay_lf_ratio']
properties.flReflectionsGain = value['reflections_gain']
properties.flReflectionsDelay = value['reflections_delay']
properties.flReflectionsPan[0] = value['reflections_pan'][0]
properties.flReflectionsPan[1] = value['reflections_pan'][1]
properties.flReflectionsPan[2] = value['reflections_pan'][2]
properties.flLateReverbGain = value['late_reverb_gain']
properties.flLateReverbDelay = value['late_reverb_delay']
properties.flLateReverbPan[0] = value['late_reverb_pan'][0]
properties.flLateReverbPan[1] = value['late_reverb_pan'][1]
properties.flLateReverbPan[2] = value['late_reverb_pan'][2]
properties.flEchoTime = value['echo_time']
properties.flEchoDepth = value['echo_depth']
properties.flModulationTime = value['modulation_time']
properties.flModulationDepth = value['modulation_depth']
properties.flAirAbsorptionGainHF = value['air_absorption_gain_hf']
properties.flHFReference = value['hf_reference']
properties.flLFReference = value['lf_reference']
properties.flRoomRolloffFactor = value['room_rolloff_factor']
properties.iDecayHFLimit = value['decay_hf_limit']
self.impl.set_reverb_properties(properties)
self.slot.apply_effect(self.impl)
@setter
def chorus_properties(self, value: dict) -> None:
"""The effect with the specified chorus properties.
Raises
------
RuntimeError
If the chorus effect is not supported.
"""
cdef alure.EFXCHORUSPROPERTIES properties
properties.iWaveform = value['waveform']
properties.iPhase = value['phase']
properties.flRate = value['rate']
properties.flDepth = value['depth']
properties.flFeedback = value['feedback']
properties.flDelay = value['delay']
self.impl.set_chorus_properties(properties)
self.slot.apply_effect(self.impl)
def destroy(self) -> None:
"""Destroy the effect slot, returning it to the system.
@ -2065,59 +2043,362 @@ cdef class Effect:
self.impl.destroy()
cdef class SendPath:
"""Container of write-only descriptors of a send path signal."""
cdef alure.Source source
cdef unsigned send
cdef class ReverbEffect(BaseEffect):
"""EAXReverb effect.
def __init__(self, source: Source, send: int) -> None:
self.source = source.impl
self.send = send
It will automatically downgrade to the Standard Reverb effect
if EAXReverb effect is not supported.
@setter
def filter(self, value: Vector3) -> None:
"""Linear gains on the send path signal, clamped to [0, 1].
Parameters
----------
preset : str, optional
The initial preset to start with, falling back to GENERIC.
context : Optional[Context], optional
The context from which the effect is to be created.
By default `current_context()` is used.
Parameters
----------
gain : float
Linear gain applying to all frequencies, default to 1.
gain_hf : float
Linear gain applying to high frequencies, default to 1.
gain_lf : float
Linear gain applying to low frequencies, default to 1.
"""
gain, gain_hf, gain_lf = value
self.source.set_send_filter(
self.send, make_filter(gain, gain_hf, gain_lf))
@setter
def effect(self, value: Effect) -> None:
"""Effect applied to the send path signal."""
self.source.set_auxiliary_send(value.slot, self.send)
cdef class AuxiliarySends:
"""Collection of SendPath.
It is recommended that applications access instances of
this class via `Source.sends`. From there, one can get a `SendPath`
by indexing the object with a nonnegative integer less than
the device's `max_auxiliary_sends`.
Raises
------
ValueError
If the specified preset cannot be found in `reverb_preset_names`.
RuntimeError
If there is neither any context specified nor current.
"""
cdef Source source
cdef alure.EFXEAXREVERBPROPERTIES properties
def __init__(self, source: Source) -> None:
self.source = source
def __getitem__(self, key: int) -> SendPath:
if not isinstance(key, int):
raise TypeError(
f'integer key expected, got {key.__class__.__name__}')
def __init__(self, preset: str = 'GENERIC',
context: Optional[Context] = None) -> None:
super().__init__(context)
try:
return SendPath(self.source, key)
except OverflowError:
raise IndexError(f'index out of range: {key}') from None
self.properties = REVERB_PRESETS.at(preset.upper())
except IndexError:
raise ValueError(f'invalid preset name: {preset}') from None
else:
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
@setter
def send_auto(self, value: bool) -> None:
"""Whether to automatically adjust send slot gains."""
self.slot.set_send_auto(value)
@property
def density(self) -> float:
return self.properties.density
@density.setter
def density(self, value: float) -> None:
self.properties.density = value
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def diffusion(self) -> float:
return self.properties.diffusion
@diffusion.setter
def diffusion(self, value: float) -> None:
self.properties.diffusion = value
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def gain(self) -> float:
return self.properties.gain
@gain.setter
def gain(self, value: float) -> None:
self.properties.gain = value
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def gain_hf(self) -> float:
return self.properties.gain_hf
@gain_hf.setter
def gain_hf(self, value: float) -> None:
self.properties.gain_hf = value
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def gain_lf(self) -> float:
return self.properties.gain_lf
@gain_lf.setter
def gain_lf(self, value: float) -> None:
self.properties.gain_lf = value
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def decay_time(self) -> float:
return self.properties.decay_time
@decay_time.setter
def decay_time(self, value: float) -> None:
self.properties.decay_time = value
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def decay_hf_ratio(self) -> float:
return self.properties.decay_hf_ratio
@decay_hf_ratio.setter
def decay_hf_ratio(self, value: float) -> None:
self.properties.decay_hf_ratio = value
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def decay_lf_ratio(self) -> float:
return self.properties.decay_lf_ratio
@decay_lf_ratio.setter
def decay_lf_ratio(self, value: float) -> None:
self.properties.decay_lf_ratio = value
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def reflections_gain(self) -> float:
return self.properties.reflections_gain
@reflections_gain.setter
def reflections_gain(self, value: float) -> None:
self.properties.reflections_gain = value
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def reflections_delay(self) -> float:
return self.properties.reflections_delay
@reflections_delay.setter
def reflections_delay(self, value: float) -> None:
self.properties.reflections_delay = value
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def reflections_pan(self) -> Vector3:
return self.properties.reflections_pan
@reflections_pan.setter
def reflections_pan(self, value: Vector3) -> None:
self.properties.reflections_pan[0] = value[0]
self.properties.reflections_pan[1] = value[1]
self.properties.reflections_pan[2] = value[2]
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def late_reverb_gain(self) -> float:
return self.properties.late_reverb_gain
@late_reverb_gain.setter
def late_reverb_gain(self, value: float) -> None:
self.properties.late_reverb_gain = value
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def late_reverb_delay(self) -> float:
return self.properties.late_reverb_delay
@late_reverb_delay.setter
def late_reverb_delay(self, value: float) -> None:
self.properties.late_reverb_delay = value
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def late_reverb_pan(self) -> Vector3:
return self.properties.late_reverb_pan
@late_reverb_pan.setter
def late_reverb_pan(self, value: Vector3) -> None:
self.properties.late_reverb_pan[0] = value[0]
self.properties.late_reverb_pan[1] = value[1]
self.properties.late_reverb_pan[2] = value[2]
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def echo_time(self) -> float:
return self.properties.echo_time
@echo_time.setter
def echo_time(self, value: float) -> None:
self.properties.echo_time = value
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def echo_depth(self) -> float:
return self.properties.echo_depth
@echo_depth.setter
def echo_depth(self, value: float) -> None:
self.properties.echo_depth = value
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def modulation_time(self) -> float:
return self.properties.modulation_time
@modulation_time.setter
def modulation_time(self, value: float) -> None:
self.properties.modulation_time = value
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def modulation_depth(self) -> float:
return self.properties.modulation_depth
@modulation_depth.setter
def modulation_depth(self, value: float) -> None:
self.properties.modulation_depth = value
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def air_absorption_gain_hf(self) -> float:
return self.properties.air_absorption_gain_hf
@air_absorption_gain_hf.setter
def air_absorption_gain_hf(self, value: float) -> None:
self.properties.air_absorption_gain_hf = value
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def hf_reference(self) -> float:
return self.properties.hf_reference
@hf_reference.setter
def hf_reference(self, value: float) -> None:
self.properties.hf_reference = value
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def lf_reference(self) -> float:
return self.properties.lf_reference
@lf_reference.setter
def lf_reference(self, value: float) -> None:
self.properties.lf_reference = value
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def room_rolloff_factor(self) -> float:
return self.properties.room_rolloff_factor
@room_rolloff_factor.setter
def room_rolloff_factor(self, value: float) -> None:
self.properties.room_rolloff_factor = value
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def decay_hf_limit(self) -> int:
return self.properties.decay_hf_limit
@decay_hf_limit.setter
def decay_hf_limit(self, value: int) -> None:
self.properties.decay_hf_limit = value
self.impl.set_reverb_properties(self.properties)
self.slot.apply_effect(self.impl)
cdef class ChorusEffect(BaseEffect):
"""Chorus effect.
Parameters
----------
waveform : int
phase : int
depth : float
feedback : float
delay : float
context : Optional[Context], optional
The context from which the effect is to be created.
By default `current_context()` is used.
Raises
------
RuntimeError
If there is neither any context specified nor current.
"""
cdef alure.EFXCHORUSPROPERTIES properties
def __init__(self, waveform: int, phase: int,
depth: float, feedback: float, delay: float,
context: Optional[Context] = None) -> None:
super().__init__(context)
self.properties.waveform = waveform
self.properties.phase = phase
self.properties.depth = depth
self.properties.feedback = feedback
self.properties.delay = delay
self.impl.set_chorus_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def waveform(self) -> int:
return self.properties.waveform
@waveform.setter
def waveform(self, value: int) -> None:
self.properties.waveform = value
self.impl.set_chorus_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def phase(self) -> int:
return self.properties.phase
@phase.setter
def phase(self, value: int) -> None:
self.properties.phase = value
self.impl.set_chorus_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def depth(self) -> float:
return self.properties.depth
@depth.setter
def depth(self, value: float) -> None:
self.properties.depth = value
self.impl.set_chorus_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def feedback(self) -> float:
return self.properties.feedback
@feedback.setter
def feedback(self, value: float) -> None:
self.properties.feedback = value
self.impl.set_chorus_properties(self.properties)
self.slot.apply_effect(self.impl)
@property
def delay(self) -> float:
return self.properties.delay
@delay.setter
def delay(self, value: float) -> None:
self.properties.delay = value
self.impl.set_chorus_properties(self.properties)
self.slot.apply_effect(self.impl)
cdef class Decoder:

View File

@ -1,5 +1,6 @@
# Effect pytest module
# Copyright (C) 2020 Ngô Ngọc Đức Huy
# Copyright (C) 2020 Nguyễn Gia Phong
#
# This file is part of palace.
#
@ -16,15 +17,15 @@
# You should have received a copy of the GNU Lesser General Public License
# along with palace. If not, see <https://www.gnu.org/licenses/>.
"""This pytest module tries to test the correctness of the class Effect."""
"""This pytest module verifies environmental effects."""
from palace import Effect, Source
from palace import BaseEffect, ReverbEffect, Source
from pytest import raises
def test_gain(context):
"""Test write-only property `gain`."""
with Effect() as fx:
"""Test write-only property gain."""
with BaseEffect() as fx:
fx.gain = 0
fx.gain = 1
fx.gain = 5/7
@ -32,29 +33,28 @@ def test_gain(context):
with raises(ValueError): fx.gain = -1
def test_send_auto(context):
"""Test write-only property `send_auto`."""
with Effect() as fx:
fx.send_auto = False
fx.send_auto = True
with raises(TypeError): fx.gain = None
def test_source_sends(context):
"""Test property `source_sends` by assigning it to a source."""
with Source() as src, Effect() as fx:
"""Test property source_sends by assigning it to a source."""
with Source() as src, BaseEffect() as fx:
src.sends[0].effect = fx
assert fx.source_sends[-1] == (src, 0)
def test_use_count(context):
"""Test read-only property `use_count`."""
with Effect() as fx:
"""Test read-only property use_count."""
with BaseEffect() as fx:
assert fx.use_count == len(fx.source_sends)
def test_reverb_preset(context):
"""Test write-only property `reverb_preset`."""
with Effect() as fx:
fx.reverb_preset = 'GENERIC'
with raises(ValueError): fx.reverb_preset = 'NOT_AN_EFFECT'
def test_reverb(context):
"""Test ReverbEffect initialization."""
with ReverbEffect('DRUGGED'): pass
with raises(ValueError):
with ReverbEffect('NOT_AN_EFFECT'): pass
def test_reverb_send_auto(context):
"""Test ReverbEffect's write-only property send_auto."""
with ReverbEffect() as fx:
fx.send_auto = False
fx.send_auto = True

View File

@ -23,7 +23,7 @@ from math import inf, pi
from operator import is_
from random import random, shuffle
from palace import Buffer, Effect, Source, SourceGroup
from palace import Buffer, BaseEffect, Source, SourceGroup
from pytest import raises
from fmath import FLT_MAX, allclose, isclose
@ -293,7 +293,7 @@ def test_gain_auto(context):
def tests_sends(device, context):
"""Test send paths assignment."""
with Source() as source, Effect() as effect:
with Source() as source, BaseEffect() as effect:
invalid_filter = [-1, 0, 1]
for i in range(device.max_auxiliary_sends):
source.sends[i].effect = effect

View File

@ -7,14 +7,11 @@ isolated_build = true
setenv =
CYTHON_TRACE = 1
deps =
flake8
Cython
scipy
pytest-flake8
pytest-cov
pytest-timeout
commands =
flake8
pytest
commands = pytest
[flake8]
filename = *.pxd, *.pyx, *.py
@ -25,7 +22,7 @@ per-file-ignores = *.pxd:E501,E999
;max-doc-length = 72
[pytest]
addopts = --cov=palace
addopts = --flake8 --cov=palace
[coverage:run]
plugins = Cython.Coverage