211 lines
5.3 KiB
Python
211 lines
5.3 KiB
Python
import math
|
|
import pytest
|
|
from pojagi_dsp.channel import (
|
|
ASignal,
|
|
Constantly,
|
|
Filter,
|
|
FilterFunction,
|
|
SignalFunction,
|
|
IllegalStateException,
|
|
Reduce,
|
|
)
|
|
from pojagi_dsp.channel.generator.sine import SineWave
|
|
|
|
|
|
@pytest.fixture
|
|
def srate():
|
|
return 44100
|
|
|
|
|
|
@pytest.fixture
|
|
def freq():
|
|
return 440
|
|
|
|
|
|
@pytest.fixture
|
|
def const(srate):
|
|
return Constantly(42, srate=srate)
|
|
|
|
|
|
@pytest.fixture
|
|
def sine(srate, freq):
|
|
return SineWave(freq, srate=srate)
|
|
|
|
|
|
@pytest.fixture
|
|
def sine_generator_factory(srate, freq):
|
|
def sine():
|
|
phase = 0.0
|
|
inc = (2 * math.pi * freq) / srate
|
|
while True:
|
|
yield math.sin(phase)
|
|
phase += inc
|
|
|
|
return sine
|
|
|
|
|
|
def test_missing_srate_assigned_from_kwarg_reader(const: ASignal):
|
|
pipeline = Filter(reader=const)
|
|
assert pipeline.srate == const.srate
|
|
|
|
|
|
def test_missing_srate_assigned_from_ored_reader(const: ASignal):
|
|
pipeline = const | Filter
|
|
assert pipeline.srate == const.srate
|
|
|
|
|
|
def test_add_operator(const: Constantly):
|
|
cursor = (const + 1).stream()
|
|
assert next(cursor) == const.constant + 1
|
|
|
|
|
|
def test_mul_operator(const: Constantly):
|
|
cursor = (const * 100).stream()
|
|
assert next(cursor) == const.constant * 100
|
|
|
|
|
|
def test_filter_iterable(const: Constantly):
|
|
pipeline = const | (Filter, Filter, Filter)
|
|
assert pipeline.reader.reader.reader == const
|
|
assert next(pipeline) == const.constant == next(const)
|
|
|
|
|
|
def test_filter_expression(const: Constantly):
|
|
pipeline = const | (Filter | Filter | Filter)
|
|
assert pipeline.reader.reader.reader == const
|
|
assert next(pipeline) == const.constant == next(const)
|
|
|
|
|
|
def test_filter_nested_expression(const: Constantly):
|
|
pipeline = const | (Filter | (Filter, Filter) | (Filter | Filter) | Filter)
|
|
assert pipeline.reader.reader.reader.reader.reader.reader == const
|
|
assert next(pipeline) == const.constant == next(const)
|
|
|
|
|
|
def test_reader(const: Constantly):
|
|
filter = Filter()
|
|
with pytest.raises(IllegalStateException, match=".reader. is None"):
|
|
filter.reader
|
|
assert (const | filter).reader == const
|
|
|
|
|
|
def test_pipeline_missing_reader(const: ASignal):
|
|
pipeline = Filter | Filter | Filter
|
|
with pytest.raises(IllegalStateException, match=".reader. is None"):
|
|
next(pipeline)
|
|
assert next(const | pipeline)
|
|
|
|
|
|
def test_filter_can_only_be_assigned_one_generator(const: Constantly):
|
|
pipeline = const | Filter | Filter
|
|
|
|
with pytest.raises(ValueError, match="already has a generator"):
|
|
Constantly(0) | pipeline
|
|
|
|
|
|
def test_add_tuple(const: Constantly):
|
|
pipeline = const + (100, 200, 300)
|
|
assert isinstance(pipeline, Reduce)
|
|
assert next(pipeline) == const.constant + (100 + 200 + 300)
|
|
|
|
|
|
def test_mul_tuple(const: Constantly):
|
|
pipeline = const * (100, 200, 300)
|
|
assert isinstance(pipeline, Reduce)
|
|
assert next(pipeline) == const.constant * (100 * 200 * 300)
|
|
|
|
|
|
def test_radd(const: Constantly):
|
|
pipeline = 1 + const
|
|
assert next(pipeline) == const.constant + 1
|
|
|
|
|
|
def test_radd_tuple(const: Constantly):
|
|
pipeline = (1, 2, 3) + const
|
|
assert next(pipeline) == const.constant + (1 + 2 + 3)
|
|
|
|
|
|
def test_rmul(const: Constantly):
|
|
pipeline = 2 * const
|
|
assert next(pipeline) == const.constant * 2
|
|
|
|
|
|
def test_rmul_tuple(const: Constantly):
|
|
pipeline = (2, 3, 4) * const
|
|
assert next(pipeline) == const.constant * (2 * 3 * 4)
|
|
|
|
|
|
def test_samples(sine: SineWave, sine_generator_factory):
|
|
pipeline = sine | Filter
|
|
cursor = pipeline.samples()
|
|
cursor2 = sine_generator_factory()
|
|
for val in cursor:
|
|
assert val == next(cursor2)
|
|
|
|
|
|
def test_stream(sine: SineWave, sine_generator_factory):
|
|
pipeline = sine | Filter
|
|
cursor = pipeline.stream()
|
|
cursor2 = sine_generator_factory()
|
|
for _ in range(5):
|
|
assert next(cursor) == next(cursor2)
|
|
|
|
|
|
def test_cursor(sine: SineWave, sine_generator_factory):
|
|
pipeline = sine | Filter
|
|
cursor1 = pipeline.cursor
|
|
cursor2 = pipeline.cursor
|
|
cursor3 = sine_generator_factory()
|
|
assert cursor1 == cursor2
|
|
for v1 in cursor1:
|
|
assert v1 == next(cursor3)
|
|
|
|
with pytest.raises(StopIteration):
|
|
next(cursor2)
|
|
|
|
|
|
def test_iter(sine: SineWave):
|
|
count = 0
|
|
for _ in sine:
|
|
count += 1
|
|
assert count == math.ceil(sine.wavelength)
|
|
for _ in sine:
|
|
count += 1
|
|
assert count == math.ceil(sine.wavelength * 2)
|
|
|
|
|
|
def test_next(sine: SineWave):
|
|
pipeline = sine | Filter
|
|
for _ in range(5):
|
|
val = next(pipeline)
|
|
assert type(val) == float
|
|
assert val != next(pipeline)
|
|
|
|
|
|
def test_function_filter(const: Constantly):
|
|
pipeline = const | FilterFunction(lambda r: (x + 1 for x in r))
|
|
assert next(pipeline) == const.constant + 1
|
|
|
|
|
|
def test_filter_function_literal(const: Constantly):
|
|
pipeline = const | (lambda r: (x + 1 for x in r))
|
|
assert next(pipeline) == const.constant + 1
|
|
|
|
|
|
def test_signal_function(sine: SineWave, sine_generator_factory):
|
|
pipeline = SignalFunction(lambda _: sine.samples(), srate=srate) | Filter
|
|
sine_generator = sine_generator_factory()
|
|
for _ in range(5):
|
|
assert next(sine_generator) == next(pipeline)
|
|
|
|
|
|
def test_sine_mod(sine: SineWave):
|
|
seconds = 10
|
|
stream = sine.stream()
|
|
for _ in range(sine.srate * seconds):
|
|
next(stream)
|
|
assert sine.phase <= (2 * math.pi)
|
|
|
|
for _ in sine:
|
|
assert sine.phase <= (2 * math.pi)
|