libcsound 0.18.2__tar.gz → 0.18.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {libcsound-0.18.2 → libcsound-0.18.4}/PKG-INFO +1 -1
- {libcsound-0.18.2 → libcsound-0.18.4}/libcsound/_install.py +43 -251
- {libcsound-0.18.2 → libcsound-0.18.4}/libcsound/_util.py +36 -21
- {libcsound-0.18.2 → libcsound-0.18.4}/libcsound/data/getcsound.ps1 +100 -29
- libcsound-0.18.4/libcsound/data/getcsound.sh +949 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/libcsound.egg-info/PKG-INFO +1 -1
- {libcsound-0.18.2 → libcsound-0.18.4}/libcsound.egg-info/SOURCES.txt +0 -1
- {libcsound-0.18.2 → libcsound-0.18.4}/libcsound.egg-info/scm_file_list.json +0 -1
- libcsound-0.18.4/libcsound.egg-info/scm_version.json +8 -0
- libcsound-0.18.2/libcsound/_terminal.py +0 -114
- libcsound-0.18.2/libcsound/data/getcsound.sh +0 -506
- libcsound-0.18.2/libcsound.egg-info/scm_version.json +0 -8
- {libcsound-0.18.2 → libcsound-0.18.4}/.github/workflows/test.yml +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/AGENTS.md +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/LICENSE +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/MANIFEST.in +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/README.rst +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/cmake/csound-custom-macos.cmake +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/docs/Makefile +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/docs/_static/custom.css +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/docs/conf.py +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/docs/csound6.rst +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/docs/csound7.rst +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/docs/index.rst +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/docs/introduction.rst +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/docs/make.bat +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/docs/notebooks/01-Introduction.ipynb +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/docs/notebooks/02-Threading.ipynb +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/docs/notebooks/no-queue.png +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/docs/notebooks/no-queue.wav +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/docs/notebooks/threading-example1.mp3 +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/docs/notebooks/threading-example2.mp3 +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/docs/notebooks/with-queue.wav +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/docs/notebooks.rst +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/docs/porting.rst +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/docs/requirements.txt +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/libcsound/__init__.py +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/libcsound/_dll.py +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/libcsound/api6.py +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/libcsound/api7.py +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/libcsound/common.py +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/libcsound/py.typed +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/libcsound.egg-info/dependency_links.txt +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/libcsound.egg-info/requires.txt +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/libcsound.egg-info/top_level.txt +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/pyproject.toml +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/setup.cfg +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/test/actions-test1.py +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/test/actionstest.csd +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/test/bufferInOut.csd +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/test/check-installer-sync.py +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/test/linux-install-render.py +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/test/macos-install-render.py +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/test/numpfields.csd +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/test/simple1.csd +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/test/simple2.csd +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/test/test-numpfields.py +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/test/test0.py +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/test/test1.py +0 -0
- {libcsound-0.18.2 → libcsound-0.18.4}/test/windows-install-render.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: libcsound
|
|
3
|
-
Version: 0.18.
|
|
3
|
+
Version: 0.18.4
|
|
4
4
|
Summary: Python bindings to the Csound API, supporting all versions of csound higher or equal to 6.18, including csound 7
|
|
5
5
|
Author-email: Eduardo Moguillansky <eduardo.moguillansky@gmail.com>
|
|
6
6
|
License: GNU LESSER GENERAL PUBLIC LICENSE
|
|
@@ -1,139 +1,18 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
import ctypes as ct
|
|
3
|
-
import hashlib
|
|
4
3
|
from pathlib import Path
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import sys
|
|
5
|
+
import os
|
|
7
6
|
from .common import logger
|
|
8
|
-
from
|
|
9
|
-
|
|
7
|
+
from typing import Sequence
|
|
10
8
|
|
|
11
|
-
def print_download_info(url: str, target: str) -> None:
|
|
12
|
-
"""Print a compact, colored summary of an imminent download."""
|
|
13
|
-
stream = sys.stdout
|
|
14
|
-
asset = os.path.basename(target)
|
|
15
|
-
target_dir = os.path.dirname(target) or "."
|
|
16
9
|
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
def stdin_is_tty() -> bool:
|
|
11
|
+
"""Return True if stdin is an interactive terminal."""
|
|
19
12
|
try:
|
|
20
|
-
|
|
13
|
+
return bool(sys.stdin is not None and not sys.stdin.closed and sys.stdin.isatty())
|
|
21
14
|
except Exception:
|
|
22
|
-
|
|
23
|
-
rule = rule_char * max(0, width - 4)
|
|
24
|
-
|
|
25
|
-
print()
|
|
26
|
-
print(f" {title}")
|
|
27
|
-
print(f" {rule}")
|
|
28
|
-
for label, value, color in (
|
|
29
|
-
("source:", url, "blue"),
|
|
30
|
-
("target:", target_dir, "blue"),
|
|
31
|
-
):
|
|
32
|
-
label_text = paint(f"{label:<8}", "bold", stream=stream)
|
|
33
|
-
value_text = paint(value, color, stream=stream)
|
|
34
|
-
print(f" {label_text} {value_text}")
|
|
35
|
-
print()
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def hexdigest(path: str) -> str:
|
|
39
|
-
hashsum = hashlib.sha256()
|
|
40
|
-
with open(path, "rb") as f:
|
|
41
|
-
for chunk in iter(lambda: f.read(65536), b""):
|
|
42
|
-
hashsum.update(chunk)
|
|
43
|
-
return hashsum.hexdigest()
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
def content_length(resp: Any) -> int | None:
|
|
47
|
-
try:
|
|
48
|
-
value = resp.headers.get("Content-Length")
|
|
49
|
-
if value is not None:
|
|
50
|
-
return int(value)
|
|
51
|
-
except (KeyError, TypeError, ValueError):
|
|
52
|
-
pass
|
|
53
|
-
return None
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def copy_with_progress(resp: Any, out: Any, asset: str) -> None:
|
|
57
|
-
"""Copy ``resp`` to ``out``, rendering a progress bar on stderr."""
|
|
58
|
-
import time
|
|
59
|
-
|
|
60
|
-
stream = sys.stderr
|
|
61
|
-
tty = stream_is_tty(stream)
|
|
62
|
-
total = content_length(resp)
|
|
63
|
-
start = time.monotonic()
|
|
64
|
-
done = 0
|
|
65
|
-
last_render = 0.0
|
|
66
|
-
last_render_done = -1
|
|
67
|
-
interval = 0.1 if tty else 0.5
|
|
68
|
-
while True:
|
|
69
|
-
chunk = resp.read(65536)
|
|
70
|
-
if not chunk:
|
|
71
|
-
break
|
|
72
|
-
out.write(chunk)
|
|
73
|
-
done += len(chunk)
|
|
74
|
-
now = time.monotonic()
|
|
75
|
-
if now - last_render >= interval:
|
|
76
|
-
render_progress_line(stream, asset, done, total, now - start, tty)
|
|
77
|
-
last_render = now
|
|
78
|
-
last_render_done = done
|
|
79
|
-
if tty:
|
|
80
|
-
clear_progress_line(stream)
|
|
81
|
-
print_progress_done(stream, asset, done)
|
|
82
|
-
elif done != last_render_done:
|
|
83
|
-
render_progress_line(stream, asset, done, total,
|
|
84
|
-
time.monotonic() - start, tty)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
def download(url: str, target: str, verbose: bool = False, retries: int = 3,
|
|
88
|
-
progress: bool = False) -> None:
|
|
89
|
-
"""Download ``url`` and store it as ``target``.
|
|
90
|
-
|
|
91
|
-
Args:
|
|
92
|
-
url: Source URL.
|
|
93
|
-
target: Destination file path.
|
|
94
|
-
verbose: Print a human-readable summary of the download.
|
|
95
|
-
retries: Number of attempts before giving up.
|
|
96
|
-
progress: Show a progress bar while downloading (tty only).
|
|
97
|
-
"""
|
|
98
|
-
import time
|
|
99
|
-
import urllib.request
|
|
100
|
-
import http.client
|
|
101
|
-
import shutil
|
|
102
|
-
asset = os.path.basename(target)
|
|
103
|
-
if verbose:
|
|
104
|
-
print_download_info(url, target)
|
|
105
|
-
else:
|
|
106
|
-
logger.info("Downloading URL: %s to %s...", url, asset)
|
|
107
|
-
last_error: Exception | None = None
|
|
108
|
-
for attempt in range(1, retries + 1):
|
|
109
|
-
try:
|
|
110
|
-
req = urllib.request.Request(url, headers={"User-Agent": "libcsound"})
|
|
111
|
-
with urllib.request.urlopen(req, timeout=120) as resp, \
|
|
112
|
-
open(target, "wb") as out:
|
|
113
|
-
if progress:
|
|
114
|
-
copy_with_progress(resp, out, asset)
|
|
115
|
-
else:
|
|
116
|
-
shutil.copyfileobj(resp, out)
|
|
117
|
-
return
|
|
118
|
-
except (OSError, http.client.HTTPException, ValueError) as e:
|
|
119
|
-
# OSError covers urllib.error.URLError/HTTPError, socket and file errors;
|
|
120
|
-
# HTTPException covers BadStatusLine/IncompleteRead; ValueError covers
|
|
121
|
-
# malformed/unknown URLs.
|
|
122
|
-
last_error = e
|
|
123
|
-
if progress and stream_is_tty(sys.stderr):
|
|
124
|
-
try:
|
|
125
|
-
clear_progress_line(sys.stderr)
|
|
126
|
-
except Exception:
|
|
127
|
-
pass
|
|
128
|
-
if attempt < retries:
|
|
129
|
-
wait = 2 * attempt
|
|
130
|
-
logger.warning("Download of '%s' failed (attempt %d/%d): %s. "
|
|
131
|
-
"Retrying in %ds...",
|
|
132
|
-
asset, attempt, retries, e, wait)
|
|
133
|
-
time.sleep(wait)
|
|
134
|
-
raise RuntimeError(f"Failed to download '{asset}' from {url} "
|
|
135
|
-
f"(temporary file: {target}) after {retries} attempts\n"
|
|
136
|
-
f"{last_error}") from last_error
|
|
15
|
+
return False
|
|
137
16
|
|
|
138
17
|
|
|
139
18
|
def run_installer(cmd: Sequence[str], failure_hint: str = "") -> None:
|
|
@@ -189,18 +68,19 @@ def run_installer(cmd: Sequence[str], failure_hint: str = "") -> None:
|
|
|
189
68
|
raise RuntimeError(message)
|
|
190
69
|
|
|
191
70
|
|
|
192
|
-
def install_csound_linux() -> None:
|
|
193
|
-
"""Install
|
|
71
|
+
def install_csound_linux(quiet=True) -> None:
|
|
72
|
+
"""Install csound 7 on linux by running the bundled installer.
|
|
194
73
|
|
|
195
|
-
This
|
|
196
|
-
https://csound-plugins.github.io/getcsound.sh
|
|
74
|
+
This runs the bundled copy of the official installer at
|
|
75
|
+
https://csound-plugins.github.io/getcsound.sh with bash. The installer
|
|
76
|
+
downloads the portable csound 7 release from the
|
|
77
|
+
``csound-plugins/csound-plugins`` GitHub repository, verifies its SHA-256
|
|
78
|
+
checksum and installs it. ``--no-risset`` is always passed so that risset is
|
|
79
|
+
never installed.
|
|
197
80
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
bundled ``install.sh``. When running inside a tty the installer is run
|
|
202
|
-
interactively; otherwise it is run with ``--user -y`` so that csound is
|
|
203
|
-
installed to ``~/.local/csound``
|
|
81
|
+
When running inside a terminal the installer is run interactively;
|
|
82
|
+
otherwise it is run with ``--user -y`` so that csound is installed to
|
|
83
|
+
``~/.local/csound`` without prompting.
|
|
204
84
|
|
|
205
85
|
After a successful installation, the environment variables ``LIBCSOUNDPATH``
|
|
206
86
|
and ``OPCODE7DIR64`` point to the installed library and plugin
|
|
@@ -208,120 +88,29 @@ def install_csound_linux() -> None:
|
|
|
208
88
|
the need to open a new terminal.
|
|
209
89
|
|
|
210
90
|
Raises:
|
|
211
|
-
RuntimeError: if the
|
|
212
|
-
|
|
213
|
-
could not be located post installation.
|
|
91
|
+
RuntimeError: if the bundled installer could not be found or failed, or
|
|
92
|
+
if csound could not be located post installation.
|
|
214
93
|
"""
|
|
215
|
-
import
|
|
216
|
-
import stat
|
|
217
|
-
import tempfile
|
|
218
|
-
import zipfile
|
|
219
|
-
|
|
220
|
-
repo = "csound-plugins/csound-plugins"
|
|
221
|
-
tag = os.getenv("CSOUND7_TAG", "latest")
|
|
94
|
+
import importlib.resources
|
|
222
95
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
arch = "x86_64"
|
|
227
|
-
elif machine in ("aarch64", "arm64"):
|
|
228
|
-
arch = "aarch64"
|
|
229
|
-
else:
|
|
230
|
-
raise RuntimeError(f"Unsupported architecture: {machine}. "
|
|
231
|
-
"Supported architectures: x86_64, aarch64.")
|
|
232
|
-
|
|
233
|
-
asset = os.getenv("CSOUND7_ASSET", f"csound7-linux-{arch}.zip")
|
|
234
|
-
checksum_asset = f"{asset}.sha256"
|
|
235
|
-
if tag == 'latest':
|
|
236
|
-
# Notice how github changes the format to address the latest release
|
|
237
|
-
base_url = f"https://github.com/{repo}/releases/latest/download"
|
|
238
|
-
else:
|
|
239
|
-
# Here this is a real tag, it must exist
|
|
240
|
-
base_url = f"https://github.com/{repo}/releases/download/{tag}"
|
|
241
|
-
|
|
242
|
-
checksum_url = f"{base_url}/{checksum_asset}"
|
|
243
|
-
|
|
244
|
-
with tempfile.TemporaryDirectory(prefix="libcsound-install-") as tmpdir:
|
|
245
|
-
zip_path = os.path.join(tmpdir, asset)
|
|
246
|
-
checksum_path = f"{zip_path}.sha256"
|
|
247
|
-
download(f"{base_url}/{asset}", zip_path, verbose=True,
|
|
248
|
-
progress=stdin_is_tty())
|
|
249
|
-
download(checksum_url, checksum_path)
|
|
250
|
-
|
|
251
|
-
# Verify SHA256 checksum before extracting
|
|
252
|
-
try:
|
|
253
|
-
with open(checksum_path, encoding="utf-8") as f:
|
|
254
|
-
tokens = f.readline().split()
|
|
255
|
-
except (OSError, UnicodeDecodeError) as e:
|
|
256
|
-
raise RuntimeError(
|
|
257
|
-
f"Could not read the checksum file downloaded from {checksum_url}: {e}"
|
|
258
|
-
) from e
|
|
259
|
-
expected = tokens[0] if tokens else ""
|
|
260
|
-
actual = hexdigest(zip_path)
|
|
261
|
-
if not expected or expected != actual:
|
|
262
|
-
raise RuntimeError(
|
|
263
|
-
f"SHA-256 checksum verification failed for {asset}\n"
|
|
264
|
-
f"Expected: {expected}\n"
|
|
265
|
-
f"Actual: {actual}\n"
|
|
266
|
-
f"The downloaded file may be corrupted or have been modified.\n"
|
|
267
|
-
f"Checksum URL: {checksum_url}")
|
|
268
|
-
logger.info("Checksum verified.")
|
|
269
|
-
|
|
270
|
-
extract_dir = os.path.join(tmpdir, "extracted")
|
|
271
|
-
try:
|
|
272
|
-
zip_size = os.path.getsize(zip_path)
|
|
273
|
-
except OSError:
|
|
274
|
-
zip_size = -1
|
|
275
|
-
try:
|
|
276
|
-
with zipfile.ZipFile(zip_path) as zf:
|
|
277
|
-
zf.extractall(extract_dir)
|
|
278
|
-
except zipfile.BadZipFile as e:
|
|
279
|
-
raise RuntimeError(
|
|
280
|
-
f"The downloaded archive '{asset}' is not a valid zip file "
|
|
281
|
-
f"(size: {zip_size} bytes, temporary file: {zip_path}): {e}"
|
|
282
|
-
) from e
|
|
283
|
-
except zipfile.LargeZipFile as e:
|
|
284
|
-
raise RuntimeError(
|
|
285
|
-
f"The downloaded archive '{asset}' requires 64-bit zip support "
|
|
286
|
-
f"(size: {zip_size} bytes, temporary file: {zip_path}): {e}"
|
|
287
|
-
) from e
|
|
288
|
-
except NotImplementedError as e:
|
|
289
|
-
# Unsupported compression method.
|
|
290
|
-
raise RuntimeError(
|
|
291
|
-
f"The downloaded archive '{asset}' uses an unsupported "
|
|
292
|
-
f"compression method (temporary file: {zip_path}): {e}"
|
|
293
|
-
) from e
|
|
294
|
-
except OSError as e:
|
|
295
|
-
raise RuntimeError(
|
|
296
|
-
f"Could not extract the downloaded archive '{asset}' "
|
|
297
|
-
f"(temporary file: {zip_path}, extract dir: {extract_dir}): {e}"
|
|
298
|
-
) from e
|
|
299
|
-
|
|
300
|
-
# Locate the bundled installer
|
|
301
|
-
for root, _dirs, files in os.walk(extract_dir):
|
|
302
|
-
if "install.sh" in files:
|
|
303
|
-
installer = os.path.join(root, "install.sh")
|
|
304
|
-
break
|
|
305
|
-
else:
|
|
306
|
-
raise RuntimeError(f"install.sh was not found inside {asset}")
|
|
96
|
+
installer = importlib.resources.files(__package__).joinpath("data", "getcsound.sh")
|
|
97
|
+
if not installer.is_file():
|
|
98
|
+
raise RuntimeError(f"The bundled installer was not found: {installer}")
|
|
307
99
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
# no terminal: install for the current user, answering yes to all
|
|
323
|
-
# questions so that the installer does not block on any prompt
|
|
324
|
-
run_installer([installer, "--user", "-y"])
|
|
100
|
+
# as_file() yields a real filesystem path, extracting to a temporary file
|
|
101
|
+
# first when the package is loaded from an archive (e.g. a zip).
|
|
102
|
+
linux_hint = ("csound can also be installed manually:\n"
|
|
103
|
+
" curl -fsSL https://csound-plugins.github.io/getcsound.sh | bash")
|
|
104
|
+
with importlib.resources.as_file(installer) as script:
|
|
105
|
+
options = ["bash", str(script), "--no-risset"]
|
|
106
|
+
if not stdin_is_tty():
|
|
107
|
+
# No terminal (e.g. on CI): install for the current user and answer
|
|
108
|
+
# yes to any prompt, so that no password is needed and the installer
|
|
109
|
+
# does not block waiting for input.
|
|
110
|
+
options.extend(["--user", "-y"])
|
|
111
|
+
if quiet:
|
|
112
|
+
options.append("--quiet")
|
|
113
|
+
run_installer(options, failure_hint=linux_hint)
|
|
325
114
|
|
|
326
115
|
# Make the freshly installed csound available to the current process
|
|
327
116
|
home = Path.home()
|
|
@@ -346,7 +135,7 @@ def install_csound_linux() -> None:
|
|
|
346
135
|
"libcsound64.so was not found in any of the standard locations")
|
|
347
136
|
|
|
348
137
|
|
|
349
|
-
def install_csound_macos() -> None:
|
|
138
|
+
def install_csound_macos(quiet=True) -> None:
|
|
350
139
|
"""Install the latest csound 7 .pkg for macOS by running the bundled installer.
|
|
351
140
|
|
|
352
141
|
The official Csound 7 macOS package is produced by the "csound_builds"
|
|
@@ -382,8 +171,11 @@ def install_csound_macos() -> None:
|
|
|
382
171
|
"terminal (or passwordless sudo).\n"
|
|
383
172
|
"Alternatively, csound can be installed manually:\n"
|
|
384
173
|
" curl -fsSL https://csound-plugins.github.io/getcsound.sh | bash")
|
|
174
|
+
args = ["bash", str(installer)]
|
|
175
|
+
if quiet:
|
|
176
|
+
args.append("--quiet")
|
|
385
177
|
with importlib.resources.as_file(installer) as script:
|
|
386
|
-
run_installer(
|
|
178
|
+
run_installer(args, failure_hint=macos_hint)
|
|
387
179
|
|
|
388
180
|
# Make the freshly installed csound available to the current process
|
|
389
181
|
csound_dir = Path("/Applications/Csound")
|
|
@@ -139,10 +139,11 @@ def testCsound(module: str = '',
|
|
|
139
139
|
ksmps=64,
|
|
140
140
|
outdev='',
|
|
141
141
|
nchnls=2,
|
|
142
|
-
dur=
|
|
142
|
+
dur=4.,
|
|
143
143
|
signal='pinker() * 0.2',
|
|
144
144
|
opcodeDir='',
|
|
145
|
-
options: list[str] | None = None
|
|
145
|
+
options: list[str] | None = None,
|
|
146
|
+
|
|
146
147
|
) -> None:
|
|
147
148
|
"""
|
|
148
149
|
Test csound
|
|
@@ -156,29 +157,32 @@ def testCsound(module: str = '',
|
|
|
156
157
|
nchnls: number of output channels
|
|
157
158
|
signal: which signal to use. Any valid sound-generating csound code
|
|
158
159
|
"""
|
|
159
|
-
from . import Csound
|
|
160
|
+
from . import Csound, getSystemSr
|
|
160
161
|
csound = Csound(opcodeDir=opcodeDir)
|
|
162
|
+
if not module:
|
|
163
|
+
module = defaultRealtimeModule()
|
|
164
|
+
csound.setOption(f'-+rtaudio={module}')
|
|
165
|
+
if options is None:
|
|
166
|
+
options = []
|
|
161
167
|
|
|
162
|
-
if outdev:
|
|
163
|
-
if module:
|
|
164
|
-
csound.setOption(f'-+rtaudio={module}')
|
|
165
|
-
csound.setOption(f'-o{outdev}')
|
|
166
|
-
else:
|
|
167
|
-
if not module:
|
|
168
|
-
module = defaultRealtimeModule()
|
|
169
|
-
csound.setOption(f'-+rtaudio={module}')
|
|
168
|
+
if not outdev:
|
|
170
169
|
if module == 'jack':
|
|
171
|
-
|
|
170
|
+
outdev = 'dac:_'
|
|
172
171
|
else:
|
|
173
|
-
|
|
172
|
+
outdev = 'dac'
|
|
173
|
+
csound.setOption(f'-o{outdev}')
|
|
174
174
|
|
|
175
175
|
if sr <= 0:
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
if
|
|
180
|
-
for
|
|
181
|
-
|
|
176
|
+
sr, _ = getSystemSr(module=module)
|
|
177
|
+
# csound.setOption('--use-system-sr')
|
|
178
|
+
csound.setOption(f'--sample-rate={sr}')
|
|
179
|
+
if module == 'jack':
|
|
180
|
+
if not any(option.startswith("-B") for option in options):
|
|
181
|
+
options.append("-B2048")
|
|
182
|
+
options.append("-b1024")
|
|
183
|
+
|
|
184
|
+
for opt in options:
|
|
185
|
+
csound.setOption(opt)
|
|
182
186
|
|
|
183
187
|
csound.compileOrc(fr"""
|
|
184
188
|
0dbfs = 1
|
|
@@ -200,8 +204,19 @@ def testCsound(module: str = '',
|
|
|
200
204
|
pt = csound.performanceThread()
|
|
201
205
|
pt.play()
|
|
202
206
|
pt.scoreEvent(False, "i", [1, 0, dur])
|
|
203
|
-
|
|
204
|
-
|
|
207
|
+
running = True
|
|
208
|
+
|
|
209
|
+
def _sigint(*args, **kws):
|
|
210
|
+
nonlocal running
|
|
211
|
+
pt.stop()
|
|
212
|
+
restoreSigint()
|
|
213
|
+
running = False
|
|
214
|
+
|
|
215
|
+
setupSigint(_sigint)
|
|
216
|
+
import time
|
|
217
|
+
while running and dur > 0:
|
|
218
|
+
time.sleep(0.1)
|
|
219
|
+
dur -= 0.1
|
|
205
220
|
restoreSigint()
|
|
206
221
|
pt.stop()
|
|
207
222
|
csound.stop()
|