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)