csoundengine 2.22.7__tar.gz → 2.23.1__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.
Files changed (134) hide show
  1. {csoundengine-2.22.7 → csoundengine-2.23.1}/.github/workflows/test2.yml +38 -0
  2. {csoundengine-2.22.7 → csoundengine-2.23.1}/PKG-INFO +11 -6
  3. {csoundengine-2.22.7 → csoundengine-2.23.1}/README.rst +7 -2
  4. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/csoundlib.py +26 -105
  5. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/dependencies.py +19 -79
  6. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/engine.py +13 -2
  7. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/enginebase.py +3 -4
  8. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/offlineengine.py +14 -2
  9. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine.egg-info/PKG-INFO +11 -6
  10. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine.egg-info/SOURCES.txt +2 -2
  11. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine.egg-info/requires.txt +2 -2
  12. csoundengine-2.23.1/docs/Installation.rst +15 -0
  13. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/Introduction.rst +3 -2
  14. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/index.rst +2 -1
  15. {csoundengine-2.22.7 → csoundengine-2.23.1}/pyproject.toml +6 -6
  16. csoundengine-2.23.1/test/testdeps.py +46 -0
  17. csoundengine-2.22.7/.cirrus.yml +0 -40
  18. csoundengine-2.22.7/docs/Installation.rst +0 -19
  19. {csoundengine-2.22.7 → csoundengine-2.23.1}/.gitignore +0 -0
  20. {csoundengine-2.22.7 → csoundengine-2.23.1}/LICENSE.txt +0 -0
  21. {csoundengine-2.22.7 → csoundengine-2.23.1}/MANIFEST.in +0 -0
  22. {csoundengine-2.22.7 → csoundengine-2.23.1}/cmake/csound-custom-macos.cmake +0 -0
  23. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/__init__.py +0 -0
  24. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/_common.py +0 -0
  25. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/_palette.py +0 -0
  26. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/abstractrenderer.py +0 -0
  27. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/baseschedevent.py +0 -0
  28. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/busproxy.py +0 -0
  29. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/config.py +0 -0
  30. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/contants.py +0 -0
  31. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/csd.py +0 -0
  32. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/csounddefs.py +0 -0
  33. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/csoundparse.py +0 -0
  34. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/engineorc.py +0 -0
  35. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/errors.py +0 -0
  36. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/event.py +0 -0
  37. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/instr.py +0 -0
  38. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/instrtools.py +0 -0
  39. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/interact.py +0 -0
  40. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/internal.py +0 -0
  41. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/jacktools.py +0 -0
  42. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/jupytertools.py +0 -0
  43. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/linuxaudio.py +0 -0
  44. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/magic.py +0 -0
  45. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/offline.py +0 -0
  46. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/offlineorc.py +0 -0
  47. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/paramtable.py +0 -0
  48. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/plotting.py +0 -0
  49. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/py.typed +0 -0
  50. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/renderjob.py +0 -0
  51. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/schedevent.py +0 -0
  52. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/session.py +0 -0
  53. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/sessionhandler.py +0 -0
  54. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/sessioninstrs.py +0 -0
  55. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/sftools.py +0 -0
  56. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/state.py +0 -0
  57. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/synth.py +0 -0
  58. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/tableproxy.py +0 -0
  59. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine/tools.py +0 -0
  60. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine.egg-info/dependency_links.txt +0 -0
  61. {csoundengine-2.22.7 → csoundengine-2.23.1}/csoundengine.egg-info/top_level.txt +0 -0
  62. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/Builtin-Opcodes.rst +0 -0
  63. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/Makefile +0 -0
  64. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/Reference.rst +0 -0
  65. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/_static/custom.css +0 -0
  66. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/_static/offlineengine-example1.mp3 +0 -0
  67. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/assets/config-edit.png +0 -0
  68. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/assets/eventui.png +0 -0
  69. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/assets/eventui2.png +0 -0
  70. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/assets/jupyter-config.png +0 -0
  71. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/assets/jupyter-plotTable.png +0 -0
  72. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/assets/jupyter-session-1.png +0 -0
  73. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/assets/offlineengine-example1.png +0 -0
  74. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/assets/select-preset.png +0 -0
  75. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/assets/synthui.png +0 -0
  76. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/assets/tableplot-sine.png +0 -0
  77. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/assets/tableplot-stereo.png +0 -0
  78. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/assets/tableproxy-plot.png +0 -0
  79. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/assets/tableproxy-plotspectrogram.png +0 -0
  80. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/assets/ui2.png +0 -0
  81. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/conf.py +0 -0
  82. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/config.rst +0 -0
  83. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/configkeys.rst +0 -0
  84. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/csoundengine.rst +0 -0
  85. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/csoundlib.rst +0 -0
  86. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/instr.rst +0 -0
  87. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/jupyternotebook.rst +0 -0
  88. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/magics.rst +0 -0
  89. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/make.bat +0 -0
  90. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/offline.rst +0 -0
  91. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/offlineengine.rst +0 -0
  92. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/offlineengine_example.inc +0 -0
  93. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/offlineengine_example2.inc +0 -0
  94. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/offlinerenderer.rst +0 -0
  95. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/renderjob.rst +0 -0
  96. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/requirements.txt +0 -0
  97. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/schedevent.rst +0 -0
  98. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/session.rst +0 -0
  99. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/synth.rst +0 -0
  100. {csoundengine-2.22.7 → csoundengine-2.23.1}/docs/tables.rst +0 -0
  101. {csoundengine-2.22.7 → csoundengine-2.23.1}/notebooks/buses.ipynb +0 -0
  102. {csoundengine-2.22.7 → csoundengine-2.23.1}/notebooks/offlineengine-playback.ipynb +0 -0
  103. {csoundengine-2.22.7 → csoundengine-2.23.1}/notebooks/offlineengine.ipynb +0 -0
  104. {csoundengine-2.22.7 → csoundengine-2.23.1}/notebooks/snd/colours-german-male.flac +0 -0
  105. {csoundengine-2.22.7 → csoundengine-2.23.1}/notebooks/snd/piano-pitchtest-2.flac +0 -0
  106. {csoundengine-2.22.7 → csoundengine-2.23.1}/notebooks/snd/voiceover-fragment-48k.flac +0 -0
  107. {csoundengine-2.22.7 → csoundengine-2.23.1}/notebooks/test/plltrack.ipynb +0 -0
  108. {csoundengine-2.22.7 → csoundengine-2.23.1}/notebooks/test/test-bus.ipynb +0 -0
  109. {csoundengine-2.22.7 → csoundengine-2.23.1}/notebooks/test/test-dealloc-synth.ipynb +0 -0
  110. {csoundengine-2.22.7 → csoundengine-2.23.1}/notebooks/test/test-delay.ipynb +0 -0
  111. {csoundengine-2.22.7 → csoundengine-2.23.1}/notebooks/test/test-engine-params.ipynb +0 -0
  112. {csoundengine-2.22.7 → csoundengine-2.23.1}/notebooks/test/test-libcsound.ipynb +0 -0
  113. {csoundengine-2.22.7 → csoundengine-2.23.1}/notebooks/test/test-named-events.ipynb +0 -0
  114. {csoundengine-2.22.7 → csoundengine-2.23.1}/notebooks/test/test-new-named-params.ipynb +0 -0
  115. {csoundengine-2.22.7 → csoundengine-2.23.1}/notebooks/test/test-offline-render.ipynb +0 -0
  116. {csoundengine-2.22.7 → csoundengine-2.23.1}/notebooks/test/test-offlinesession.ipynb +0 -0
  117. {csoundengine-2.22.7 → csoundengine-2.23.1}/notebooks/test/test-params.ipynb +0 -0
  118. {csoundengine-2.22.7 → csoundengine-2.23.1}/notebooks/test/test-playsample.ipynb +0 -0
  119. {csoundengine-2.22.7 → csoundengine-2.23.1}/notebooks/test/test-stop.ipynb +0 -0
  120. {csoundengine-2.22.7 → csoundengine-2.23.1}/notebooks/test/test-tight-scheduling.ipynb +0 -0
  121. {csoundengine-2.22.7 → csoundengine-2.23.1}/notebooks/test/test-whenfinished.ipynb +0 -0
  122. {csoundengine-2.22.7 → csoundengine-2.23.1}/notebooks/voice-pitch-track.ipynb +0 -0
  123. {csoundengine-2.22.7 → csoundengine-2.23.1}/pyrightconfig.json +0 -0
  124. {csoundengine-2.22.7 → csoundengine-2.23.1}/readthedocs.yml +0 -0
  125. {csoundengine-2.22.7 → csoundengine-2.23.1}/scripts/download-plugins.py +0 -0
  126. {csoundengine-2.22.7 → csoundengine-2.23.1}/scripts/update-config-docs.py +0 -0
  127. {csoundengine-2.22.7 → csoundengine-2.23.1}/setup.cfg +0 -0
  128. {csoundengine-2.22.7 → csoundengine-2.23.1}/test/importtime.py +0 -0
  129. {csoundengine-2.22.7 → csoundengine-2.23.1}/test/libcsoundtest.py +0 -0
  130. {csoundengine-2.22.7 → csoundengine-2.23.1}/test/simple.py +0 -0
  131. {csoundengine-2.22.7 → csoundengine-2.23.1}/test/test1.csd +0 -0
  132. {csoundengine-2.22.7 → csoundengine-2.23.1}/test/test1.py +0 -0
  133. {csoundengine-2.22.7 → csoundengine-2.23.1}/test/test2.py +0 -0
  134. {csoundengine-2.22.7 → csoundengine-2.23.1}/test/testargs.py +0 -0
@@ -169,3 +169,41 @@ jobs:
169
169
  with:
170
170
  name: artifact-csound7-${{ matrix.os }}-${{ matrix.python-version }}-${{ strategy.job-index }}
171
171
  path: test/*.wav
172
+
173
+ testdeps:
174
+ name: Check that all dependencies are installed without a system csound
175
+ # csound is not preinstalled on these runners. Importing libcsound (which
176
+ # happens when importing csoundengine) is expected to install csound and
177
+ # its plugins on demand.
178
+ # ubuntu-latest -> linux x86_64, macos-latest -> macos arm64
179
+ # (intentionally not linux-arm64 nor windows, where this is not supported)
180
+ runs-on: ${{ matrix.os }}
181
+ strategy:
182
+ matrix:
183
+ os: ["ubuntu-latest", "macos-latest"]
184
+ python-version: ["3.12", "3.13"]
185
+ fail-fast: false
186
+
187
+ steps:
188
+ - uses: actions/checkout@v3
189
+
190
+ - uses: actions/setup-python@v4
191
+ with:
192
+ python-version: ${{ matrix.python-version }}
193
+
194
+ - name: check that csound is not preinstalled
195
+ run: |
196
+ if command -v csound; then
197
+ echo "ERROR: this test expects csound to not be installed beforehand"
198
+ exit 1
199
+ fi
200
+ echo "csound is not preinstalled, good"
201
+
202
+ - name: install csoundengine (csound is not installed on purpose)
203
+ run: |
204
+ pip install .
205
+
206
+ - name: check that all dependencies (csound, plugins) get installed
207
+ run: |
208
+ cd test
209
+ python testdeps.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: csoundengine
3
- Version: 2.22.7
3
+ Version: 2.23.1
4
4
  Summary: An audio synthesis framework using csound
5
5
  Author-email: Eduardo Moguillansky <eduardo.moguillansky@gmail.com>
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -680,7 +680,7 @@ License: GNU GENERAL PUBLIC LICENSE
680
680
  Project-URL: Homepage, https://github.com/gesellkammer/csoundengine
681
681
  Classifier: Programming Language :: Python :: 3
682
682
  Classifier: Operating System :: OS Independent
683
- Requires-Python: >=3.10
683
+ Requires-Python: >=3.12
684
684
  Description-Content-Type: text/x-rst
685
685
  License-File: LICENSE.txt
686
686
  Requires-Dist: numpy
@@ -695,12 +695,12 @@ Requires-Dist: ipywidgets
695
695
  Requires-Dist: xxhash
696
696
  Requires-Dist: docstring_parser
697
697
  Requires-Dist: typing_extensions
698
- Requires-Dist: libcsound>=0.12.0
698
+ Requires-Dist: libcsound>=0.17.0
699
699
  Requires-Dist: sndfileio>=2.1.1
700
700
  Requires-Dist: emlib>=1.20
701
701
  Requires-Dist: configdict>=2.10.0
702
702
  Requires-Dist: pitchtools>=1.14.0
703
- Requires-Dist: risset>=3.2.2
703
+ Requires-Dist: risset>=3.5.4
704
704
  Requires-Dist: sounddevice
705
705
  Dynamic: license-file
706
706
 
@@ -885,8 +885,13 @@ https://csoundengine.readthedocs.io/en/latest/Installation.html
885
885
  Dependencies
886
886
  ~~~~~~~~~~~~
887
887
 
888
- * python >= 3.9
889
- * csound 6 >= 6.17 (https://github.com/csound/csound/releases). Csound 7 is supported and recommended
888
+ * python >= 3.12
889
+ * csound 7 >= 7.0 (csound 6 is supported but it is declared EOL)
890
+
891
+ .. note::
892
+ csound only needs to be installed previously on windows at the moment, for
893
+ the other platforms it is installed automatically if not present
894
+
890
895
 
891
896
  .. code-block:: bash
892
897
 
@@ -179,8 +179,13 @@ https://csoundengine.readthedocs.io/en/latest/Installation.html
179
179
  Dependencies
180
180
  ~~~~~~~~~~~~
181
181
 
182
- * python >= 3.9
183
- * csound 6 >= 6.17 (https://github.com/csound/csound/releases). Csound 7 is supported and recommended
182
+ * python >= 3.12
183
+ * csound 7 >= 7.0 (csound 6 is supported but it is declared EOL)
184
+
185
+ .. note::
186
+ csound only needs to be installed previously on windows at the moment, for
187
+ the other platforms it is installed automatically if not present
188
+
184
189
 
185
190
  .. code-block:: bash
186
191
 
@@ -39,16 +39,12 @@ if TYPE_CHECKING:
39
39
  logger = _logging.getLogger("csoundengine")
40
40
 
41
41
 
42
- _cache: dict[str, Any] = {
43
- 'opcodes': None,
44
- 'versionTriplet': None
45
- }
46
-
47
-
48
42
  _audioDeviceRegex = r"(\d+):\s((?:adc|dac)\d+)\s*\((.*)\)(?:\s+\[ch:(\d+)\])?"
49
43
 
50
44
 
51
- def midiDevices(backend='portmidi') -> tuple[list[MidiDevice], list[MidiDevice]]:
45
+ def midiDevices(backend='portmidi',
46
+ opcodedir=''
47
+ ) -> tuple[list[MidiDevice], list[MidiDevice]]:
52
48
  """
53
49
  Returns input and output midi devices for the given backend
54
50
 
@@ -71,7 +67,7 @@ def midiDevices(backend='portmidi') -> tuple[list[MidiDevice], list[MidiDevice]]
71
67
  ======== ===========================
72
68
  """
73
69
  import libcsound
74
- csound = libcsound.Csound()
70
+ csound = libcsound.Csound(opcodeDir=opcodedir)
75
71
  csound.setOption(f"-+rtmidi={backend}")
76
72
  csound.setOption("-odac")
77
73
  csound.start()
@@ -146,7 +142,7 @@ class AudioBackend:
146
142
  indevices, outdevices = getAudioDevices(backend=self.name)
147
143
  return bool(indevices or outdevices)
148
144
 
149
- def getSystemSr(self) -> int | None:
145
+ def getSystemSr(self, opcodedir='') -> int | None:
150
146
  """
151
147
  Get the system samplerate for this backend, if available
152
148
 
@@ -156,7 +152,7 @@ class AudioBackend:
156
152
  logger.debug(f"Backend {self.name} does not have a system sr, returning default")
157
153
  return 44100
158
154
  import libcsound
159
- cs = libcsound.Csound()
155
+ cs = libcsound.Csound(opcodeDir=opcodedir)
160
156
  cs.setOption("-odac")
161
157
  cs.setOption(f"-+rtaudio={self.name}")
162
158
  ok = cs.start()
@@ -176,7 +172,8 @@ class AudioBackend:
176
172
  def audioDevices(self) -> tuple[list[AudioDevice], list[AudioDevice]]:
177
173
  return self.audioDevicesViaAPI()
178
174
 
179
- def audioDevicesViaAPI(self) -> tuple[list[AudioDevice], list[AudioDevice]]:
175
+ def audioDevicesViaAPI(self, opcodedir=''
176
+ ) -> tuple[list[AudioDevice], list[AudioDevice]]:
180
177
  """
181
178
  Query csound for audio devices for this backend
182
179
 
@@ -185,7 +182,7 @@ class AudioBackend:
185
182
  """
186
183
  logger.info(f"Querying csound's audio devices for backend {self.name}")
187
184
  import libcsound
188
- cs = libcsound.Csound()
185
+ cs = libcsound.Csound(opcodeDir=opcodedir)
189
186
  cs.createMessageBuffer()
190
187
  for opt in ['-+rtaudio='+self.name, "-m16", "-odac", "--use-system-sr"]:
191
188
  cs.setOption(opt)
@@ -398,6 +395,8 @@ class _AlsaBackend(AudioBackend):
398
395
 
399
396
  @_functools.cache
400
397
  def _getAvailableAudioBackends() -> dict[str, AudioBackend]:
398
+ # This is not correct, we should actually check which plugins
399
+ # are available
401
400
  _backendPortaudioCallback = _PortaudioBackend('callback')
402
401
 
403
402
  backends: dict[str, AudioBackend] = {
@@ -411,7 +410,6 @@ def _getAvailableAudioBackends() -> dict[str, AudioBackend]:
411
410
 
412
411
  if sys.platform == 'linux':
413
412
  backends['alsa'] = _AlsaBackend()
414
- backends['pulseaudio'] = _PulseAudioBackend()
415
413
  elif sys.platform == 'darwin':
416
414
  auhal = AudioBackend('auhal', alwaysAvailable=True, hasSystemSr=True,
417
415
  needsRealtime=False, longname="coreaudio",
@@ -436,17 +434,7 @@ def findCsound() -> str | None:
436
434
  return csound
437
435
 
438
436
 
439
- def _getVersionViaApi() -> tuple[int, int, int]:
440
- """
441
- Returns the csound version as tuple (major, minor, patch)
442
- """
443
- if (version := _cache.get('versionTriplet')) is not None:
444
- return version
445
- return _csoundGetInfoViaAPI()['versionTriplet']
446
-
447
-
448
- @_functools.cache
449
- def getVersion(useApi=True) -> tuple[int, int, int | str]:
437
+ def getVersion(opcodedir='') -> tuple[int, int, int | str]:
450
438
  """
451
439
  Returns the csound version as tuple (major, minor, patch)
452
440
 
@@ -461,34 +449,7 @@ def getVersion(useApi=True) -> tuple[int, int, int | str]:
461
449
  Raises RuntimeError if csound is not present or its version
462
450
  can't be parsed
463
451
  """
464
- if useApi:
465
- return _getVersionViaApi()
466
-
467
- csound = findCsound()
468
- if not csound:
469
- raise IOError("Csound not found")
470
- cmd = '{csound} --version'.format(csound=csound).split()
471
- proc = _subprocess.Popen(cmd, stderr=_subprocess.PIPE)
472
- proc.wait()
473
- if proc.stderr is None:
474
- return (0, 0, 0)
475
- outputbytes = proc.stderr.read()
476
- if not outputbytes:
477
- raise RuntimeError("Could not read csounds output")
478
- output = outputbytes.decode('utf8')
479
- lines = output.splitlines()
480
- for line in lines:
481
- if match := _re.search(r"Csound\s+version\s+(\d+)\.(\d+)(\.\w+)?", line):
482
- major = int(match.group(1))
483
- minor = int(match.group(2))
484
- patch = match.group(3)
485
- if patch is None:
486
- patch = 0
487
- elif patch.isdigit():
488
- patch = int(patch)
489
- return (major, minor, patch)
490
- else:
491
- raise RuntimeError(f"Did not find a csound version, csound output: '{output}'")
452
+ return csoundGetInfo(opcodedir=opcodedir)['versionTriplet']
492
453
 
493
454
 
494
455
  def csoundSubproc(args: list[str], piped=True, wait=False) -> _subprocess.Popen:
@@ -555,28 +516,6 @@ def getSystemSr(backend: str) -> float | None:
555
516
  return b.getSystemSr()
556
517
 
557
518
 
558
- # def _getJackSrViaClient() -> float:
559
- # import jack
560
- # c = jack.Client("query")
561
- # sr = c.samplerate
562
- # c.close()
563
- # return sr
564
-
565
-
566
- # def _getCsoundSystemSr(backend: str) -> float:
567
- # if backend not in {'jack', 'auhal'}:
568
- # raise ValueError(f"backend {backend} does not support system sr")
569
- # import libcsound
570
- # csound = libcsound.Csound()
571
- # csound.setOption(f"-+rtaudio={backend}")
572
- # csound.setOption("-odac")
573
- # csound.setOption("--use-system-sr")
574
- # csound.start()
575
- # sr = csound.sr()
576
- # csound.stop()
577
- # return sr
578
-
579
-
580
519
  def getDefaultBackend() -> AudioBackend:
581
520
  """
582
521
  Get the default active backend for platform
@@ -740,6 +679,7 @@ def testCsound(dur=8., nchnls=2, backend='', device="dac", sr=0, ksmps=64,
740
679
  sr = {sr}
741
680
  ksmps = {ksmps}
742
681
  nchnls = {nchnls}
682
+ 0dbfs = 1
743
683
 
744
684
  instr 1
745
685
  iperiod = 1
@@ -775,22 +715,22 @@ def installedOpcodes(cached=True, opcodedir: str = '') -> set[str]:
775
715
  Returns:
776
716
  a list of all available opcodes
777
717
  """
778
- if opcodedir:
779
- cached = False
780
- if cached and _cache.get('opcodes') is not None:
781
- return _cache['opcodes']
782
- return _csoundGetInfoViaAPI(opcodedir=opcodedir)['opcodes']
718
+ #if not cached:
719
+ # csoundGetInfo.cache_clear()
720
+ return csoundGetInfo(opcodedir=opcodedir)['opcodes']
783
721
 
784
722
 
785
- def _csoundGetInfoViaAPI(opcodedir='') -> dict:
786
- global _cache
723
+ # @_functools.cache
724
+ def csoundGetInfo(opcodedir='') -> dict:
725
+ """
726
+ Returns a dict of {'opcodedefs': list[OpcodeDef], 'opcodes': set[str], 'versionTriplet': (major, minor, patch)}
727
+
728
+ """
787
729
  import libcsound
788
- cs = libcsound.Csound()
730
+ cs = libcsound.Csound(opcodeDir=opcodedir)
789
731
  cs.setOption("-d")
790
732
  cs.setOption("--nosound")
791
733
  cs.createMessageBuffer(echo=False)
792
- if opcodedir:
793
- cs.setOption(f'--opcode-dir={opcodedir}')
794
734
  version = cs.version()
795
735
  vs = str(version)
796
736
  patch = int(vs[-1])
@@ -798,33 +738,14 @@ def _csoundGetInfoViaAPI(opcodedir='') -> dict:
798
738
  major = int(vs[:-3])
799
739
  versionTriplet = (major, minor, patch)
800
740
  opcodes = cs.getOpcodes()
801
- opcodenames = set(opc.name for opc in opcodes)
802
- _cache['versionTriplet'] = versionTriplet
803
- _cache['opcodes'] = opcodenames
804
- _cache['opcodedefs'] = opcodes
805
741
  cs.stop()
742
+ cs.destroy()
743
+ opcodenames = {opc.name.split(".")[0] for opc in opcodes}
806
744
  return {'opcodedefs': opcodes,
807
745
  'opcodes': opcodenames,
808
746
  'versionTriplet': versionTriplet}
809
747
 
810
748
 
811
- # def _opcodesList(opcodedir='') -> list[str]:
812
- # options = ["-z"]
813
- # if opcodedir:
814
- # options.append(f'--opcode-dir={opcodedir}')
815
- # s = csoundSubproc(options)
816
- # assert s.stderr is not None
817
- # lines = s.stderr.readlines()
818
- # allopcodes = []
819
- # for line in lines:
820
- # if line.startswith(b"end of score"):
821
- # break
822
- # opcodes = line.decode('utf8').split()
823
- # if opcodes:
824
- # allopcodes.extend(opcodes)
825
- # return allopcodes
826
-
827
-
828
749
  def saveAsGen23(data: Sequence[float] | np.ndarray,
829
750
  outfile: str,
830
751
  fmt="%.12f",
@@ -10,9 +10,7 @@ import tempfile
10
10
  from datetime import datetime
11
11
  from pathlib import Path
12
12
 
13
- from . import tools
14
13
  from .state import state
15
- from . import csounddefs
16
14
 
17
15
 
18
16
  logger = logging.getLogger("csoundengine.dependencies")
@@ -151,13 +149,17 @@ def pluginsInstalled(cached=True) -> bool:
151
149
  from . import csoundlib
152
150
  installedOpcodes = csoundlib.installedOpcodes(cached=cached)
153
151
  neededOpcodes = {
154
- "atstop", "pwrite", "pread", "initerror",
155
- "dict_new", "dict_set", "dict_get",
156
- "pool_gen", "pool_pop", "pool_push", "pool_isfull",
152
+ "atstop", "pwrite",
153
+ "dict_new", "pool_gen", "pool_pop", "pool_push",
157
154
  'interp1d', 'bisect', 'ftsetparams', 'zeroarray',
158
155
  'panstereo'
159
156
  }
160
- return neededOpcodes.issubset(installedOpcodes)
157
+ ok = neededOpcodes.issubset(installedOpcodes)
158
+ if not ok:
159
+ notfound = neededOpcodes - installedOpcodes
160
+ logger.debug("Opcodes not found: %s", notfound)
161
+ logger.debug("Opcodes found: %s...", sorted(installedOpcodes)[:20])
162
+ return ok
161
163
 
162
164
 
163
165
  def _getDownloadsFolder() -> Path:
@@ -169,44 +171,6 @@ def _getDownloadsFolder() -> Path:
169
171
  return tempdir
170
172
 
171
173
 
172
- def _installPluginsFromDist(apiversion=6, codesign=True) -> None:
173
- platformid = tools.platformId()
174
- rootfolder = Path(os.path.split(__file__)[0])
175
- assert rootfolder.exists()
176
- globpattern = {
177
- 'macos': '*.dylib',
178
- 'windows': '*.dll',
179
- 'linux': '*.so'
180
- }.get(platformid.osname, None)
181
- if globpattern is None:
182
- raise RuntimeError(f"Platform {platformid} not supported")
183
-
184
- subfolder = str(platformid)
185
- pluginspath = rootfolder/f'data/plugins{apiversion}'/subfolder
186
- if not pluginspath.exists():
187
- raise RuntimeError(f"Could not find own csound plugins. Folder: {pluginspath}")
188
- plugins = list(pluginspath.glob(globpattern))
189
- if not plugins:
190
- logger.error(f"Plugins not found. Plugins folder: '{pluginspath}', "
191
- f"glob patter: '{globpattern}'")
192
- raise RuntimeError("Plugins not found")
193
- pluginsDest = csounddefs.userPluginsFolder(apiversion=f'{apiversion}.0')
194
- logger.info(f"Installing plugins in folder: '{pluginsDest}'")
195
- os.makedirs(pluginsDest, exist_ok=True)
196
- _copyFiles([plugin.as_posix() for plugin in plugins], pluginsDest, verbose=True)
197
- if platformid.osname == 'macos' and codesign:
198
- installedBinaries = [os.path.join(pluginsDest, plugin.name)
199
- for plugin in plugins]
200
- assert all(os.path.exists(binary) for binary in installedBinaries)
201
- try:
202
- _codesignBinaries(installedBinaries)
203
- except RuntimeError as e:
204
- logger.error(f"Could not code-sign the binaries, error: {e}")
205
- if platformid.arch == 'arm64':
206
- logger.error(f"... The needed plugins will probably not work as is. You can still "
207
- f"manually authorize them via right-click. The paths are: {installedBinaries}")
208
-
209
-
210
174
  def _installPluginsViaRisset(majorversion: int | None = None) -> bool:
211
175
  """
212
176
  Tries to install plugins via risset
@@ -215,7 +179,7 @@ def _installPluginsViaRisset(majorversion: int | None = None) -> bool:
215
179
  """
216
180
  logger.info("Trying to install plugins via risset")
217
181
  import risset
218
- idx = risset.MainIndex(update=True, majorversion=majorversion)
182
+ idx = risset.MainIndex(update=True, major_version=majorversion or 7)
219
183
  for pluginname in ['else', 'beosc', 'klib']:
220
184
  p = idx.plugins.get(pluginname)
221
185
  if p is None:
@@ -224,10 +188,12 @@ def _installPluginsViaRisset(majorversion: int | None = None) -> bool:
224
188
  elif idx.is_plugin_installed(p):
225
189
  logger.debug(f"Plugin '{pluginname}' already installed, skipping")
226
190
  else:
191
+ logger.debug(f"Installing plugin {pluginname}")
227
192
  errmsg = idx.install_plugin(p)
228
193
  if errmsg:
229
194
  logger.error(f"Error while installing plugin {pluginname}: {errmsg}")
230
195
  return False
196
+ logger.debug("---- Installed all plugins")
231
197
  return True
232
198
 
233
199
 
@@ -251,45 +217,30 @@ def installPlugins() -> bool:
251
217
  " listed by csound")
252
218
  from . import csoundlib
253
219
  opcodes = csoundlib.installedOpcodes(cached=False)
254
- opcodestr = ', '.join(opcodes)
255
- logger.error(f"List of opcodes loaded by csound: {opcodestr}")
220
+ logger.error("List of opcodes loaded by csound: %s", ', '.join(sorted(opcodes)))
256
221
  return False
257
222
  except Exception as e:
258
223
  logger.error(f"Exception {e} while trying to install plugins via risset")
259
224
  return False
260
225
 
261
- # logger.info("Installing plugins from distribution")
262
- # try:
263
- # _installPluginsFromDist(apiversion=majorversion)
264
- # ok = pluginsInstalled(cached=False)
265
- # if ok:
266
- # logger.info("Plugins installed successfully from distribution")
267
- # else:
268
- # logger.error("Plugins where installed but do not seem to be detected")
269
- # except Exception as e:
270
- # logger.error(f"Exception {e} while trying to install plugins from distribution")
271
- # return False
272
- # return True
273
-
274
-
275
- def _checkDependencies(fix=False, quiet=False) -> str:
226
+
227
+ def _checkDependencies(fix=False) -> str:
276
228
  """
277
229
  Returns an error message on failure, or an empty string on success
278
230
  """
279
- if not csoundBinaryInPath():
280
- logger.error("csound not found in the path. See https://csound.com/download.html. Some functionality might not be available")
281
231
  from . import csoundlib
282
- version = csoundlib.getVersion(useApi=True)
232
+ info = csoundlib.csoundGetInfo()
233
+ version = info['versionTriplet']
283
234
 
284
235
  if version < (6, 16, 0):
285
236
  return f"Csound version ({version}) is too old, should be >= 6.16"
286
237
 
287
- if version[0] >= 7:
288
- logger.debug("Csound 7 support is experimental")
238
+ elif version < (7, 0, 0):
239
+ logger.info("Support for csound 6 has been deprecated, use at your own risk")
289
240
 
290
241
  if not pluginsInstalled():
291
242
  if fix:
292
- print("** csoundengine: Csound external plugins are not installed or are too old."
243
+ print("** csoundengine: Csound external plugins are not installed"
293
244
  " I will try to install them now")
294
245
  ok = installPlugins()
295
246
  if ok:
@@ -352,14 +303,3 @@ def checkDependencies(force=True, fix=False) -> bool:
352
303
  if not fix:
353
304
  logger.error("Missing dependencies might be installed by calling installDependencies()")
354
305
  return not errormsg
355
-
356
-
357
- def _codesignBinaries(binaries: list[str]) -> None:
358
- """
359
- Calls codesign to sign the binaries with adhoc signature
360
-
361
- Raises RuntimeError on fail
362
- """
363
- import risset
364
- logger.warning(f"Codesigning macos binaries: {binaries}")
365
- risset.macos_codesign(binaries, signature='-')
@@ -246,6 +246,16 @@ class Engine(_EngineBase):
246
246
  config. Default values can be configured via `config.edit()`, see
247
247
  `Configuration <https://csoundengine.readthedocs.io/en/latest/config.html>`_
248
248
 
249
+ .. note::
250
+
251
+ These env variables can customize the engine:
252
+
253
+ * LIBCSOUNDPATH: points to a valid libcsound dll. This can only be called once
254
+ within a session
255
+ * CSOUND7DIR64 / CSOUND6DIR64: path to the folder containing built-in plugins
256
+ * CS_USER_PLUGINDIR: path to the folder where user (external) plugins are placed
257
+
258
+
249
259
  Example
250
260
  -------
251
261
 
@@ -315,7 +325,8 @@ class Engine(_EngineBase):
315
325
  busSupport=False,
316
326
  nosound=False,
317
327
  useProcessQueue=False,
318
- suppressVersion=True
328
+ suppressVersion=True,
329
+ opcodeDir=''
319
330
  ):
320
331
  import libcsound as lcs
321
332
  from . import csoundlib
@@ -549,7 +560,7 @@ class Engine(_EngineBase):
549
560
  self.udpPort = 0
550
561
  "UDP port used (0 if no udp port is active)"
551
562
 
552
- self.csound: lcs.Csound = lcs.Csound()
563
+ self.csound: lcs.Csound = lcs.Csound(opcodeDir=opcodeDir)
553
564
  "The csound object"
554
565
 
555
566
  self.autosync: bool = autosync
@@ -62,13 +62,12 @@ class TableInfo:
62
62
 
63
63
 
64
64
  def _channelMode(kind: str) -> int:
65
- import libcsound
66
65
  if kind == 'r':
67
- return libcsound.CSOUND_INPUT_CHANNEL
66
+ return 16
68
67
  elif kind == 'w':
69
- return libcsound.CSOUND_INPUT_CHANNEL
68
+ return 32
70
69
  elif kind == 'rw':
71
- return libcsound.CSOUND_INPUT_CHANNEL | libcsound.CSOUND_OUTPUT_CHANNEL
70
+ return 16 | 32
72
71
  else:
73
72
  raise ValueError(f"Expected r, w or rw, got {kind}")
74
73
 
@@ -176,6 +176,15 @@ class OfflineEngine(_EngineBase):
176
176
  If no encoding is given a suitable default for the sample format is chosen.
177
177
 
178
178
 
179
+ .. note::
180
+
181
+ These env variables can customize the engine:
182
+
183
+ * LIBCSOUNDPATH: points to a valid libcsound dll. This can only be called once
184
+ within a session
185
+ * CSOUND7DIR64 / CSOUND6DIR64: path to the folder containing built-in plugins
186
+ * CS_USER_PLUGINDIR: path to the folder where user (external) plugins are placed
187
+
179
188
  """
180
189
  def __init__(self,
181
190
  sr=44100,
@@ -192,7 +201,8 @@ class OfflineEngine(_EngineBase):
192
201
  sampleAccurate=False,
193
202
  encoding='',
194
203
  nosound=False,
195
- commandlineOptions: list[str] | None = None):
204
+ commandlineOptions: list[str] | None = None,
205
+ opcodeDir=''):
196
206
  super().__init__(sr=sr,
197
207
  ksmps=ksmps,
198
208
  a4=a4 or config['A4'],
@@ -250,6 +260,8 @@ class OfflineEngine(_EngineBase):
250
260
  if commandlineOptions:
251
261
  self.options.extend(commandlineOptions)
252
262
 
263
+ self._opcodeDir = opcodeDir
264
+
253
265
  self.csound: libcsound.Csound
254
266
 
255
267
  self._start()
@@ -277,7 +289,7 @@ class OfflineEngine(_EngineBase):
277
289
  def _start(self) -> None:
278
290
  import libcsound
279
291
  self.version = libcsound.VERSION
280
- self.csound = csound = libcsound.Csound()
292
+ self.csound = csound = libcsound.Csound(opcodeDir=self._opcodeDir)
281
293
  for option in self.options:
282
294
  csound.setOption(option)
283
295
  if not self.nosound:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: csoundengine
3
- Version: 2.22.7
3
+ Version: 2.23.1
4
4
  Summary: An audio synthesis framework using csound
5
5
  Author-email: Eduardo Moguillansky <eduardo.moguillansky@gmail.com>
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -680,7 +680,7 @@ License: GNU GENERAL PUBLIC LICENSE
680
680
  Project-URL: Homepage, https://github.com/gesellkammer/csoundengine
681
681
  Classifier: Programming Language :: Python :: 3
682
682
  Classifier: Operating System :: OS Independent
683
- Requires-Python: >=3.10
683
+ Requires-Python: >=3.12
684
684
  Description-Content-Type: text/x-rst
685
685
  License-File: LICENSE.txt
686
686
  Requires-Dist: numpy
@@ -695,12 +695,12 @@ Requires-Dist: ipywidgets
695
695
  Requires-Dist: xxhash
696
696
  Requires-Dist: docstring_parser
697
697
  Requires-Dist: typing_extensions
698
- Requires-Dist: libcsound>=0.12.0
698
+ Requires-Dist: libcsound>=0.17.0
699
699
  Requires-Dist: sndfileio>=2.1.1
700
700
  Requires-Dist: emlib>=1.20
701
701
  Requires-Dist: configdict>=2.10.0
702
702
  Requires-Dist: pitchtools>=1.14.0
703
- Requires-Dist: risset>=3.2.2
703
+ Requires-Dist: risset>=3.5.4
704
704
  Requires-Dist: sounddevice
705
705
  Dynamic: license-file
706
706
 
@@ -885,8 +885,13 @@ https://csoundengine.readthedocs.io/en/latest/Installation.html
885
885
  Dependencies
886
886
  ~~~~~~~~~~~~
887
887
 
888
- * python >= 3.9
889
- * csound 6 >= 6.17 (https://github.com/csound/csound/releases). Csound 7 is supported and recommended
888
+ * python >= 3.12
889
+ * csound 7 >= 7.0 (csound 6 is supported but it is declared EOL)
890
+
891
+ .. note::
892
+ csound only needs to be installed previously on windows at the moment, for
893
+ the other platforms it is installed automatically if not present
894
+
890
895
 
891
896
  .. code-block:: bash
892
897
 
@@ -1,4 +1,3 @@
1
- .cirrus.yml
2
1
  .gitignore
3
2
  LICENSE.txt
4
3
  MANIFEST.in
@@ -127,4 +126,5 @@ test/simple.py
127
126
  test/test1.csd
128
127
  test/test1.py
129
128
  test/test2.py
130
- test/testargs.py
129
+ test/testargs.py
130
+ test/testdeps.py
@@ -10,10 +10,10 @@ ipywidgets
10
10
  xxhash
11
11
  docstring_parser
12
12
  typing_extensions
13
- libcsound>=0.12.0
13
+ libcsound>=0.17.0
14
14
  sndfileio>=2.1.1
15
15
  emlib>=1.20
16
16
  configdict>=2.10.0
17
17
  pitchtools>=1.14.0
18
- risset>=3.2.2
18
+ risset>=3.5.4
19
19
  sounddevice