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

[WIP] Slowly reworking the scheduler #257

Merged
merged 17 commits into from
Jun 16, 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
233 changes: 158 additions & 75 deletions sardine_core/handlers/midi.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
from .sender import Number, NumericElement, Sender, ParsableElement
from typing import Optional, Union
from .sender import (
Number,
NumericElement,
Sender,
ParsableElement,
_resolve_if_callable,
)
from typing import Optional, Callable
from ..utils import alias_param
from ..logger import print
import asyncio
Expand Down Expand Up @@ -173,7 +179,7 @@ def _pitch_wheel(self, pitch: int, channel: int) -> None:
self._midi.send(mido.Message("pitchweel", pitch=pitch, channel=channel))

async def send_off(
self, note: int, channel: int, velocity: int, delay: Union[int, float]
self, note: int, channel: int, velocity: int, delay: int | float
):
await self.env.sleep_beats(delay)
self._midi.send(
Expand Down Expand Up @@ -243,12 +249,12 @@ async def send_midi_note(
@alias_param(name="rate", alias="r")
def send_control(
self,
control: Optional[NumericElement] = 0,
channel: NumericElement = 0,
value: NumericElement = 60,
iterator: Number = 0,
divisor: NumericElement = 1,
rate: NumericElement = 1,
control: Optional[NumericElement] | Callable[[], NumericElement] = 0,
channel: NumericElement | Callable[[], NumericElement] = 0,
value: NumericElement | Callable[[], NumericElement] = 60,
iterator: Number | Callable[[], NumericElement] = 0,
divisor: NumericElement | Callable[[], NumericElement] = 1,
rate: NumericElement | Callable[[], NumericElement] = 1,
**rest_of_pattern: ParsableElement,
) -> None:
"""
Expand All @@ -264,10 +270,24 @@ def send_control(
):
return

pattern = {"control": control, "channel": channel, "value": value}
pattern = {
"control": _resolve_if_callable(control),
"channel": _resolve_if_callable(channel),
"value": _resolve_if_callable(value),
}

# Evaluate all potential callables
for key, value in rest_of_pattern.items():
pattern[key] = _resolve_if_callable(value)

pattern = {**self._defaults, **pattern}
deadline = self.env.clock.shifted_time
for message in self.pattern_reduce(pattern, iterator, divisor, rate):
for message in self.pattern_reduce(
pattern,
_resolve_if_callable(iterator),
_resolve_if_callable(divisor),
_resolve_if_callable(rate),
):
if None in [message["control"], message["value"]]:
continue
for k, v in message.items():
Expand All @@ -282,10 +302,10 @@ def send_control(
def send_program(
self,
channel: Optional[NumericElement],
program: NumericElement = 60,
iterator: Number = 0,
divisor: NumericElement = 1,
rate: NumericElement = 1,
program: NumericElement | Callable[[], NumericElement] = 60,
iterator: Number | Callable[[], Number] = 0,
divisor: NumericElement | Callable[[], NumericElement] = 1,
rate: NumericElement | Callable[[], NumericElement] = 1,
**rest_of_pattern: ParsableElement,
) -> None:
if channel is None:
Expand All @@ -296,10 +316,23 @@ def send_program(
):
return

pattern = {"channel": channel, "program": program}
pattern = {
"channel": _resolve_if_callable(channel),
"program": _resolve_if_callable(program),
}

# Evaluate all potential callables
for key, value in rest_of_pattern.items():
pattern[key] = _resolve_if_callable(value)

pattern = {**self._defaults, **pattern}
deadline = self.env.clock.shifted_time
for message in self.pattern_reduce(pattern, iterator, divisor, rate):
for message in self.pattern_reduce(
pattern,
_resolve_if_callable(iterator),
_resolve_if_callable(divisor),
_resolve_if_callable(rate),
):
if message["channel"] is None:
continue
for k, v in message.items():
Expand All @@ -313,12 +346,12 @@ def send_program(
@alias_param(name="rate", alias="r")
def send_sysex(
self,
data: list[int],
value: NumericElement = 60,
optional_modulo: NumericElement = 127,
iterator: Number = 0,
divisor: NumericElement = 1,
rate: NumericElement = 1,
data: list[int] | Callable[[], list[int]],
value: NumericElement | Callable[[], NumericElement] = 60,
optional_modulo: NumericElement | Callable[[], NumericElement] = 127,
iterator: Number | Callable[[], Number] = 0,
divisor: NumericElement | Callable[[], NumericElement] = 1,
rate: NumericElement | Callable[[], NumericElement] = 1,
**rest_of_pattern: ParsableElement,
) -> None:
if data is None:
Expand All @@ -329,9 +362,17 @@ def send_sysex(
):
return

pattern = {"value": value}
pattern = {"value": _resolve_if_callable(value)}

# NOTE: No need to resolve any more callables for such a simple message...

deadline = self.env.clock.shifted_time
for message in self.pattern_reduce(pattern, iterator, divisor, rate):
for message in self.pattern_reduce(
pattern,
_resolve_if_callable(iterator),
_resolve_if_callable(divisor),
_resolve_if_callable(rate),
):
if message["value"] is None:
continue
for k, v in message.items():
Expand All @@ -350,15 +391,15 @@ def send_sysex(
@alias_param(name="rate", alias="r")
def send_ziffers(
self,
ziff: str,
velocity: NumericElement = 100,
channel: NumericElement = 0,
duration: NumericElement = 1,
iterator: Number = 0,
divisor: NumericElement = 1,
rate: NumericElement = 1,
scale: str = "IONIAN",
key: str = "C4",
ziff: str | Callable[[], str],
velocity: NumericElement | Callable[[], NumericElement] = 100,
channel: NumericElement | Callable[[], NumericElement] = 0,
duration: NumericElement | Callable[[], NumericElement] = 1,
iterator: Number | Callable[[], Number] = 0,
divisor: NumericElement | Callable[[], NumericElement] = 1,
rate: NumericElement | Callable[[], NumericElement] = 1,
scale: str | Callable[[], str] = "IONIAN",
key: str | Callable[[], str] = "C4",
**rest_of_pattern: ParsableElement,
) -> int | float:
"""
Expand Down Expand Up @@ -388,15 +429,25 @@ def send_ziffers(
note = f"{{{' '.join([str(x) for x in note])}}}"

pattern = {
"note": note,
"velocity": velocity,
"channel": channel,
"duration": duration,
"note": _resolve_if_callable(note),
"velocity": _resolve_if_callable(velocity),
"channel": _resolve_if_callable(channel),
"duration": _resolve_if_callable(duration),
}

# Evaluate all potential callables
for key, value in rest_of_pattern.items():
pattern[key] = _resolve_if_callable(value)

pattern = {**self._defaults, **pattern}
deadline = self.env.clock.shifted_time

for message in self.pattern_reduce(pattern, iterator, divisor, rate):
for message in self.pattern_reduce(
pattern,
_resolve_if_callable(iterator),
_resolve_if_callable(divisor),
_resolve_if_callable(rate),
):
if message["note"] is None:
continue
for k in ("note", "velocity", "channel"):
Expand All @@ -415,14 +466,14 @@ def send_ziffers(
def send_instrument(
self,
note: Optional[NumericElement] = 60,
velocity: NumericElement = 100,
channel: NumericElement = 0,
duration: NumericElement = 1,
iterator: Number = 0,
divisor: NumericElement = 1,
rate: NumericElement = 1,
map: dict = {},
program_change: Optional[Number] = None,
velocity: NumericElement | Callable[[], NumericElement] = 100,
channel: NumericElement | Callable[[], NumericElement] = 0,
duration: NumericElement | Callable[[], NumericElement] = 1,
iterator: Number | Callable[[], Number] = 0,
divisor: NumericElement | Callable[[], NumericElement] = 1,
rate: NumericElement | Callable[[], NumericElement] = 1,
map: dict | Callable[[], dict] = {},
program_change: Optional[Number] | Callable[[], Number] = None,
**rest_of_pattern: ParsableElement,
) -> None:
"""
Expand All @@ -446,15 +497,27 @@ def send_instrument(

def note_pattern():
pattern = {
"note": note,
"velocity": velocity,
"channel": channel,
"duration": duration,
"program_change": (program_change if program_change else None),
"note": _resolve_if_callable(note),
"velocity": _resolve_if_callable(velocity),
"channel": _resolve_if_callable(channel),
"duration": _resolve_if_callable(duration),
"program_change": (
_resolve_if_callable(program_change) if program_change else None
),
}

# Evaluate all potential callables
for key, value in rest_of_pattern.items():
pattern[key] = _resolve_if_callable(value)

pattern = {**self._defaults, **pattern}
deadline = self.env.clock.shifted_time
for message in self.pattern_reduce(pattern, iterator, divisor, rate):
for message in self.pattern_reduce(
pattern,
_resolve_if_callable(iterator),
_resolve_if_callable(divisor),
_resolve_if_callable(rate),
):
if message["program_change"] is not None:
self._send_control(
program=message["program_change"], channel=message["channel"]
Expand All @@ -468,7 +531,12 @@ def note_pattern():

def send_controls(pattern: dict) -> None:
deadline = self.env.clock.shifted_time
for message in self.pattern_reduce(pattern, iterator, divisor, rate):
for message in self.pattern_reduce(
pattern,
_resolve_if_callable(iterator),
_resolve_if_callable(divisor),
_resolve_if_callable(rate),
):
if None in [message["control"], message["value"]]:
continue
for k, v in message.items():
Expand All @@ -486,11 +554,11 @@ def send_controls(pattern: dict) -> None:
@alias_param(name="rate", alias="r")
def send_controller(
self,
channel: NumericElement = 0,
iterator: Number = 0,
divisor: NumericElement = 1,
rate: NumericElement = 1,
map: dict = {},
channel: NumericElement | Callable[[], NumericElement] = 0,
iterator: Number | Callable[[], Number] = 0,
divisor: NumericElement | Callable[[], NumericElement] = 1,
rate: NumericElement | Callable[[], NumericElement] = 1,
map: dict | Callable[[], dict] = {},
**rest_of_pattern: ParsableElement,
) -> None:
"""
Expand All @@ -506,12 +574,17 @@ def send_controller(
for key, value in map.items():
if key in rest_of_pattern.keys():
control = value
control["value"] = rest_of_pattern[key]
control["value"] = _resolve_if_callable(rest_of_pattern[key])
control_messages.append(control)

def send_controls(pattern: dict) -> None:
deadline = self.env.clock.shifted_time
for message in self.pattern_reduce(pattern, iterator, divisor, rate):
for message in self.pattern_reduce(
pattern,
_resolve_if_callable(iterator),
_resolve_if_callable(divisor),
_resolve_if_callable(rate),
):
if None in [message["control"], message["value"]]:
continue
for k, v in message.items():
Expand All @@ -531,14 +604,14 @@ def send_controls(pattern: dict) -> None:
@alias_param(name="program_change", alias="pgch")
def send(
self,
note: Optional[NumericElement] = 60,
velocity: NumericElement = 100,
channel: NumericElement = 0,
duration: NumericElement = 1,
iterator: Number = 0,
divisor: NumericElement = 1,
rate: NumericElement = 1,
program_change: Optional[Number] = None,
note: Optional[NumericElement] | Callable[[], Optional[NumericElement]] = 60,
velocity: NumericElement | Callable[[], NumericElement] = 100,
channel: NumericElement | Callable[[], NumericElement] = 0,
duration: NumericElement | Callable[[], NumericElement] = 1,
iterator: Number | Callable[[], Number] = 0,
divisor: NumericElement | Callable[[], Number] = 1,
rate: NumericElement | Callable[[], NumericElement] = 1,
program_change: Optional[Number] | Callable[[], Number] = None,
**rest_of_pattern: ParsableElement,
) -> None:
"""
Expand All @@ -556,15 +629,25 @@ def send(
return

pattern = {
"note": note,
"velocity": velocity,
"channel": channel,
"duration": duration,
"program_change": program_change,
"note": _resolve_if_callable(note),
"velocity": _resolve_if_callable(velocity),
"channel": _resolve_if_callable(channel),
"duration": _resolve_if_callable(duration),
"program_change": _resolve_if_callable(program_change),
}

# Evaluate all potential callables
for key, value in rest_of_pattern.items():
pattern[key] = _resolve_if_callable(value)

pattern = {**self._defaults, **pattern}
deadline = self.env.clock.shifted_time
for message in self.pattern_reduce(pattern, iterator, divisor, rate):
for message in self.pattern_reduce(
pattern,
_resolve_if_callable(iterator),
_resolve_if_callable(divisor),
_resolve_if_callable(rate),
):
if message["program_change"] is not None:
self.send_program(
program=message["program_change"], channel=message["channel"]
Expand Down
Loading
Loading