Skip to content

Commit

Permalink
Implement server lifecycle events (#390)
Browse files Browse the repository at this point in the history
  • Loading branch information
josephine-wolf-oberholtzer authored Aug 21, 2024
1 parent edb8c0a commit 583245d
Show file tree
Hide file tree
Showing 22 changed files with 3,336 additions and 2,224 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ isort: ## Reformat via isort
lint: reformat flake8 mypy ## Run all linters

mypy: ## Type-check via mypy
mypy ${project}/
mypy ${project}/ tests/

mypy-cov: ## Type-check via mypy with coverage reported to ./mypycov/
mypy --html-report ./mypycov/ ${project}/
Expand Down
13 changes: 6 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,17 @@

Supriya lets you:

- Boot and communicate with SuperCollider's ``scsynth`` synthesis engine:
[servers](http://supriya-project.github.io/supriya/api/supriya/contexts/realtime.html)
in realtime.

- Compile SuperCollider
[SynthDefs](http://supriya-project.github.io/supriya/api/supriya/ugens/index.html)
natively in Python code
- Boot and communicate with SuperCollider's synthesis engine
in [realtime](http://supriya-project.github.io/supriya/api/supriya/contexts/realtime.html).

- Explore
[nonrealtime](http://supriya-project.github.io/supriya/api/supriya/contexts/nonrealtime.html)
composition with scores.

- Compile SuperCollider
[SynthDefs](http://supriya-project.github.io/supriya/api/supriya/ugens/index.html)
natively in Python code

- Build time-agnostic
[asyncio](https://docs.python.org/3/library/asyncio.html)-aware applications
with the
Expand Down
8 changes: 4 additions & 4 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@ Supriya (|release|)

Supriya lets you:

- Boot and communicate with SuperCollider's ``scsynth`` synthesis engine in
- Boot and communicate with SuperCollider's synthesis engine in
realtime.

- Explore :py:mod:`~supriya.contexts.nonrealtime` composition with
:py:class:`scores <supriya.contexts.nonrealtime.Score>`.

- Build time-agnostic :py:mod:`asyncio`-aware applications with the
:py:class:`context <supriya.contexts.core.Context>` interface.

- Compile SuperCollider :py:class:`SynthDefs
<supriya.ugens.bases.SynthDef>` natively in Python code.

- Build time-agnostic :py:mod:`asyncio`-aware applications with the
:py:class:`context <supriya.contexts.core.Context>` interface.

- Schedule :py:mod:`~supriya.patterns` and callbacks with tempo- and
meter-aware :py:mod:`~supriya.clocks`.

Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ classifiers = [
]
dependencies = [
"platformdirs >= 4.0.0",
"psutil",
"uqbar >= 0.7.3",
]
description = "A Python API for SuperCollider"
Expand Down
3 changes: 2 additions & 1 deletion supriya/contexts/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Tools for interacting with scsynth-compatible execution contexts.
"""

from .core import Context
from .core import BootStatus, Context
from .entities import (
Buffer,
BufferGroup,
Expand All @@ -19,6 +19,7 @@
__all__ = [
"AsyncServer",
"BaseServer",
"BootStatus",
"Buffer",
"BufferGroup",
"Bus",
Expand Down
38 changes: 37 additions & 1 deletion supriya/contexts/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import abc
import contextlib
import dataclasses
import enum
import itertools
import threading
from os import PathLike
Expand Down Expand Up @@ -101,6 +102,13 @@
)


class BootStatus(enum.IntEnum):
OFFLINE = 0
BOOTING = 1
ONLINE = 2
QUITTING = 3


@dataclasses.dataclass
class Moment:
"""
Expand Down Expand Up @@ -204,13 +212,20 @@ class Context(metaclass=abc.ABCMeta):

### INITIALIZER ###

def __init__(self, options: Optional[Options], **kwargs) -> None:
def __init__(
self,
options: Optional[Options],
name: Optional[str] = None,
**kwargs,
) -> None:
self._audio_bus_allocator = BlockAllocator()
self._boot_status = BootStatus.OFFLINE
self._buffer_allocator = BlockAllocator()
self._client_id = 0
self._control_bus_allocator = BlockAllocator()
self._latency = 0.0
self._lock = threading.RLock()
self._name = name
self._node_id_allocator = NodeIdAllocator()
self._options = new(options or Options(), **kwargs)
self._sync_id = self._sync_id_minimum = 0
Expand Down Expand Up @@ -1380,6 +1395,20 @@ def audio_output_bus_group(self) -> BusGroup:
count=self.options.output_bus_channel_count,
)

@property
def boot_status(self) -> BootStatus:
"""
Get the server's boot status.
"""
return self._boot_status

@property
def default_group(self) -> Group:
"""
Get the server's default group.
"""
return self.root_node

@property
def client_id(self) -> int:
"""
Expand All @@ -1394,6 +1423,13 @@ def latency(self) -> float:
"""
return self._latency

@property
def name(self) -> Optional[str]:
"""
Get the context's optional name.
"""
return self._name

@property
def options(self) -> Options:
"""
Expand Down
9 changes: 4 additions & 5 deletions supriya/contexts/nonrealtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
Tools for interacting with non-realtime execution contexts.
"""

import asyncio
import hashlib
import logging
import platform
Expand All @@ -22,7 +21,7 @@
from ..scsynth import AsyncNonrealtimeProcessProtocol, Options
from ..typing import HeaderFormatLike, SampleFormatLike, SupportsOsc
from ..ugens import SynthDef
from .core import Context, ContextError, ContextObject, Node
from .core import BootStatus, Context, ContextError, ContextObject, Node
from .requests import DoNothing, RequestBundle, Requestable

logger = logging.getLogger(__name__)
Expand All @@ -40,6 +39,7 @@ class Score(Context):

def __init__(self, options: Optional[Options] = None, **kwargs):
super().__init__(options=options, **kwargs)
self._boot_status = BootStatus.ONLINE
self._requests: Dict[float, List[Requestable]] = {}

### CLASS METHODS ###
Expand Down Expand Up @@ -179,10 +179,9 @@ async def render(
]
)
# render the datagram
exit_future = asyncio.get_running_loop().create_future()
protocol = AsyncNonrealtimeProcessProtocol(exit_future)
protocol = AsyncNonrealtimeProcessProtocol()
await protocol.run(command, render_directory_path_)
exit_code: int = await exit_future
exit_code: int = await protocol.exit_future
assert render_directory_path_ / render_file_name
if output_file_path_:
shutil.copy(
Expand Down
Loading

0 comments on commit 583245d

Please sign in to comment.