Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Map sound points generators to sequence #3

Merged
merged 8 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 36 additions & 2 deletions minamidera/soundpointsgenerators.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,43 @@
import numpy as np
import pang


class AtaxicSoundPointsGenerator(pang.SoundPointsGenerator):
def __init__(self, pitches_set, intensity_set, density_set, duration_set):
self.pitches_set = pitches_set
def __init__(self, pitches_set, intensity_set, density_set, duration_set, seed):
self.pitches_set = np.array(tuple(pitches_set), dtype="O")
self.intensity_set = intensity_set
self.density_set = density_set
self.duration_set = duration_set
self._random_number_generator = np.random.default_rng(seed)

def __call__(self, sequence_duration):
instances = self._generate_instances(sequence_duration)
durations = self._generate_durations(len(instances))
pitches = self._generate_pitches(len(instances))
return [
pang.SoundPoint(instance, duration, pitch)
for instance, duration, pitch in zip(
instances,
durations,
pitches,
)
]

def _generate_instances(self, sequence_duration):
(density,) = self.density_set
return sorted(
self._random_number_generator.uniform(
0.0, sequence_duration, round(density * sequence_duration)
)
)

def _generate_durations(self, number_of_sound_points):
(duration,) = self.duration_set
return self._random_number_generator.exponential(
duration, number_of_sound_points
)

def _generate_pitches(self, number_of_sound_points):
return self._random_number_generator.choice(
self.pitches_set, number_of_sound_points
).tolist()
33 changes: 24 additions & 9 deletions minamidera/statemapper.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,39 @@
from collections.abc import Iterable
from collections.abc import Collection

import numpy as np
import numpy.typing as npt
import pang

from .library import DENSITY_SETS, DURATION_SETS, INTENSITY_SETS, PITCHES_SETS
from .soundpointsgenerators import AtaxicSoundPointsGenerator


def map_state_sequence(state_sequence: Iterable[npt.NDArray]) -> pang.Sequence:
sequence = pang.Sequence.empty_sequence()
for state in state_sequence:
sequence.extend(map_state(state))
return sequence
def map_state_sequence(
state_sequence: Collection[npt.NDArray], state_duration: float, seed: int
) -> pang.Sequence:
return pang.Sequence.from_sequences(
[
map_state(state, state_duration, random_number_generator)
for state, random_number_generator in zip(
state_sequence, np.random.default_rng(seed).spawn(len(state_sequence))
)
]
)


def map_state(state: npt.NDArray) -> pang.Sequence:
raise NotImplementedError
def map_state(
state: npt.NDArray,
state_duration: float,
random_number_generator: np.random.Generator,
) -> pang.Sequence:
return pang.Sequence.from_sound_points_generator(
map_state_vector_to_sound_points_generator(state, random_number_generator),
state_duration,
)


def map_state_vector_to_sound_points_generator(
state_vector: npt.NDArray,
state_vector: npt.NDArray, seed: int | np.random.Generator
) -> pang.SoundPointsGenerator:
if len(state_vector) != 4:
raise ValueError(
Expand All @@ -34,4 +48,5 @@ def map_state_vector_to_sound_points_generator(
INTENSITY_SETS[state_vector[1]],
DENSITY_SETS[state_vector[2]],
DURATION_SETS[state_vector[3]],
seed,
)
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ allow-direct-references = true

[project]
name = "minamidera"
version = "24.8b1"
version = "24.8b2"
authors = [
{ name="Tsz Kiu Pang" },
]
Expand Down
11 changes: 11 additions & 0 deletions tests/test_soundpointgenerators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from minamidera import soundpointsgenerators


def test_generating_ataxic_sound_points():
sound_points = soundpointsgenerators.AtaxicSoundPointsGenerator(
{0, 1, 2}, {0}, {1}, {1}, 2984756
)(10)
assert sound_points != []
instances = [sound_point.instance for sound_point in sound_points]
assert instances == sorted(instances)
assert len(instances) == 10
22 changes: 17 additions & 5 deletions tests/test_statemapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,40 @@


def test_mapping_empty_sequence():
assert statemapper.map_state_sequence([]) == pang.Sequence.empty_sequence()
assert statemapper.map_state_sequence([], 10, 0) == pang.Sequence.empty_sequence()


def test_mapping_one_state_to_sequence():
sequence = statemapper.map_state_sequence([np.array([0, 1, 0, 1])], 10, 99999)
assert sequence.sequence_duration == 10


def test_mapping_100_states_to_sequence():
sequence = statemapper.map_state_sequence([np.array([0, 1, 0, 1])] * 100, 10, 99999)
assert sequence.sequence_duration == 1000


def test_mapping_sound_point_generator_from_invalid_state_vector_length():
with pytest.raises(ValueError) as exception_info:
statemapper.map_state_vector_to_sound_points_generator(
np.array([0, 0, 1, 0, 0])
np.array([0, 0, 1, 0, 0]), 982347
)
assert "does not match" in str(exception_info)


def test_mapping_sound_point_generator_from_invalid_state_vector_value():
with pytest.raises(ValueError) as exception_info:
statemapper.map_state_vector_to_sound_points_generator(np.array([0, 1, 0, 2]))
statemapper.map_state_vector_to_sound_points_generator(
np.array([0, 1, 0, 2]), 97329874
)
assert "contains value other than 0 and 1" in str(exception_info)


def test_mapping_state_vector_to_sound_point_generator():
sound_points_generator = statemapper.map_state_vector_to_sound_points_generator(
np.array([0, 1, 0, 1])
np.array([0, 1, 0, 1]), 9273894
)
assert sound_points_generator.pitches_set == library.PITCHES_SETS[0]
assert sound_points_generator.pitches_set.tolist() == list(library.PITCHES_SETS[0])
assert sound_points_generator.intensity_set == library.INTENSITY_SETS[1]
assert sound_points_generator.density_set == library.DENSITY_SETS[0]
assert sound_points_generator.duration_set == library.DURATION_SETS[1]