pym2149
Advanced tools
| # Copyright 2014, 2018, 2019, 2020 Andrzej Cichocki | ||
| # This file is part of pym2149. | ||
| # | ||
| # pym2149 is free software: you can redistribute it and/or modify | ||
| # it under the terms of the GNU General Public License as published by | ||
| # the Free Software Foundation, either version 3 of the License, or | ||
| # (at your option) any later version. | ||
| # | ||
| # pym2149 is distributed in the hope that it will be useful, | ||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| # GNU General Public License for more details. | ||
| # | ||
| # You should have received a copy of the GNU General Public License | ||
| # along with pym2149. If not, see <http://www.gnu.org/licenses/>. | ||
| class BufferFiller: | ||
| def __init__(self, portcount, buffersize, init, flip): | ||
| self.portcount = portcount | ||
| self.buffersize = buffersize | ||
| self._newbuf(init) | ||
| self.flip = flip | ||
| def __call__(self, outbufs): | ||
| n = len(outbufs[0]) | ||
| i = 0 | ||
| while i < n: | ||
| m = min(n - i, self.buffersize - self.cursor) | ||
| for portindex in range(self.portcount): | ||
| self.outbuf[portindex, self.cursor:self.cursor + m] = outbufs[portindex].buf[i:i + m] | ||
| self.cursor += m | ||
| i += m | ||
| if self.cursor == self.buffersize: | ||
| self._newbuf(self.flip) | ||
| def _newbuf(self, factory): | ||
| outbuf = factory().view() | ||
| outbuf.shape = self.portcount, self.buffersize | ||
| self.outbuf = outbuf | ||
| self.cursor = 0 |
| # Copyright 2014, 2018, 2019, 2020 Andrzej Cichocki | ||
| # This file is part of pym2149. | ||
| # | ||
| # pym2149 is free software: you can redistribute it and/or modify | ||
| # it under the terms of the GNU General Public License as published by | ||
| # the Free Software Foundation, either version 3 of the License, or | ||
| # (at your option) any later version. | ||
| # | ||
| # pym2149 is distributed in the hope that it will be useful, | ||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| # GNU General Public License for more details. | ||
| # | ||
| # You should have received a copy of the GNU General Public License | ||
| # along with pym2149. If not, see <http://www.gnu.org/licenses/>. | ||
| from . import BufferFiller | ||
| from ..const import clientname | ||
| from ..iface import AmpScale, Config, Platform, Stream | ||
| from ..nod import Node | ||
| from ..out import FloatStream, StereoInfo | ||
| from diapyr import types | ||
| import outjack.jackclient as jc, logging | ||
| log = logging.getLogger(__name__) | ||
| class JackClient(jc.JackClient, Platform): | ||
| @types(Config, StereoInfo) | ||
| def __init__(self, config, stereoinfo): | ||
| portcount = stereoinfo.getoutchans.size + config.SID.enabled # FIXME: This is a hack. | ||
| super().__init__(clientname, portcount, config.jackringsize, config.jackcoupling) | ||
| def start(self): | ||
| super().start() | ||
| log.debug( | ||
| "JACK block size: %s or %.3f seconds", | ||
| self.buffersize, | ||
| self.buffersize / self.outputrate) | ||
| class JackStream(Stream, Node, metaclass = AmpScale): | ||
| log2maxpeaktopeak = 1 | ||
| @types(Config, [FloatStream], JackClient) | ||
| def __init__(self, config, streams, client): | ||
| super().__init__() | ||
| self.systemchannelcount = config.systemchannelcount | ||
| for stream in streams: | ||
| for chanindex in range(stream.chancount): | ||
| client.port_register_output(f"{stream.streamname}_{1 + chanindex}") | ||
| self.streams = streams | ||
| self.client = client | ||
| def start(self): | ||
| self.client.activate() | ||
| for stream in self.streams: | ||
| # Connect all system channels, cycling over our streams if necessary: | ||
| for syschanindex in range(self.systemchannelcount): | ||
| chanindex = syschanindex % stream.chancount | ||
| self.client.connect(f"{clientname}:{stream.streamname}_{1 + chanindex}", f"system:playback_{1 + syschanindex}") | ||
| self.filler = BufferFiller(sum(s.chancount for s in self.streams), self.client.buffersize, self.client.current_output_buffer, self.client.send_and_get_output_buffer) | ||
| def callimpl(self): | ||
| self.filler([self.chain(wav) for stream in self.streams for wav in stream]) | ||
| def flush(self): | ||
| pass # Nothing to be done. | ||
| def stop(self): | ||
| self.client.deactivate() | ||
| def configure(di): | ||
| di.add(JackClient) | ||
| di.add(JackStream) |
| # Copyright 2014, 2018, 2019, 2020 Andrzej Cichocki | ||
| # This file is part of pym2149. | ||
| # | ||
| # pym2149 is free software: you can redistribute it and/or modify | ||
| # it under the terms of the GNU General Public License as published by | ||
| # the Free Software Foundation, either version 3 of the License, or | ||
| # (at your option) any later version. | ||
| # | ||
| # pym2149 is distributed in the hope that it will be useful, | ||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| # GNU General Public License for more details. | ||
| # | ||
| # You should have received a copy of the GNU General Public License | ||
| # along with pym2149. If not, see <http://www.gnu.org/licenses/>. | ||
| from . import BufferFiller | ||
| from ..iface import AmpScale, Config, Platform, Stream | ||
| from ..nod import Node | ||
| from ..out import FloatStream, StereoInfo | ||
| from diapyr import types | ||
| import logging, outjack.portaudioclient as pac | ||
| log = logging.getLogger(__name__) | ||
| class PortAudioClient(pac.PortAudioClient, Platform): | ||
| @types(Config, StereoInfo) | ||
| def __init__(self, config, stereoinfo): | ||
| config = config.PortAudio | ||
| super().__init__(stereoinfo.getoutchans.size, config.outputrate, config.buffersize, config.ringsize, config.coupling) | ||
| class PortAudioStream(Node, Stream, metaclass = AmpScale): | ||
| log2maxpeaktopeak = 1 | ||
| @types(StereoInfo, FloatStream, PortAudioClient) | ||
| def __init__(self, stereoinfo, wavs, client): | ||
| super().__init__() | ||
| self.chancount = stereoinfo.getoutchans.size | ||
| self.wavs = wavs | ||
| self.client = client | ||
| def start(self): | ||
| self.client.activate() | ||
| self.filler = BufferFiller(self.chancount, self.client.buffersize, self.client.current_output_buffer, self.client.send_and_get_output_buffer) | ||
| def callimpl(self): | ||
| self.filler([self.chain(wav) for wav in self.wavs]) | ||
| def flush(self): | ||
| pass | ||
| def stop(self): | ||
| self.client.deactivate() | ||
| def configure(di): | ||
| di.add(PortAudioClient) | ||
| di.add(PortAudioStream) |
+14
-5
| Metadata-Version: 2.1 | ||
| Name: pym2149 | ||
| Version: 33 | ||
| Version: 34 | ||
| Summary: YM2149 emulator supporting YM files, OSC to JACK, PortAudio, WAV | ||
| Home-page: https://github.com/combatopera/pym2149 | ||
| Author: Andrzej Cichocki | ||
| Author-email: 3613868+combatopera@users.noreply.github.com | ||
| Description-Content-Type: text/markdown | ||
| License-File: COPYING | ||
| Requires-Dist: aridity>=78 | ||
| Requires-Dist: diapyr>=26 | ||
| Requires-Dist: lagoon>=31 | ||
| Requires-Dist: Lurlene>=13 | ||
| Requires-Dist: minBlepy>=16 | ||
| Requires-Dist: numpy>=2.0.2 | ||
| Requires-Dist: outjack>=15 | ||
| Requires-Dist: pyrbo>=13 | ||
| Requires-Dist: splut>=4 | ||
| Requires-Dist: timelyOSC>=4 | ||
@@ -27,2 +38,3 @@ # pym2149 | ||
| python3 -m venv venvname | ||
| venvname/bin/pip install -U pip | ||
| venvname/bin/pip install pym2149 | ||
@@ -34,8 +46,5 @@ . venvname/bin/activate | ||
| ``` | ||
| # GitHub trick to download some files to play: | ||
| svn export https://github.com/combatopera/pym2149/trunk/contrib | ||
| # Play a tune written in the Lurlene live coding language: | ||
| lc2portaudio 'contrib/Jochen Hippel - 7 Gates of Jambala Level 9.py' | ||
| lc2jack 'contrib/Jochen Hippel - 7 Gates of Jambala Level 9.py' | ||
| lc2portaudio 'contrib/Jochen Hippel - 7 Gates of Jambala Level 9.py' | ||
@@ -42,0 +51,0 @@ # Play a Dosound sound effect: |
| Metadata-Version: 2.1 | ||
| Name: pym2149 | ||
| Version: 33 | ||
| Version: 34 | ||
| Summary: YM2149 emulator supporting YM files, OSC to JACK, PortAudio, WAV | ||
| Home-page: https://github.com/combatopera/pym2149 | ||
| Author: Andrzej Cichocki | ||
| Author-email: 3613868+combatopera@users.noreply.github.com | ||
| Description-Content-Type: text/markdown | ||
| License-File: COPYING | ||
| Requires-Dist: aridity>=78 | ||
| Requires-Dist: diapyr>=26 | ||
| Requires-Dist: lagoon>=31 | ||
| Requires-Dist: Lurlene>=13 | ||
| Requires-Dist: minBlepy>=16 | ||
| Requires-Dist: numpy>=2.0.2 | ||
| Requires-Dist: outjack>=15 | ||
| Requires-Dist: pyrbo>=13 | ||
| Requires-Dist: splut>=4 | ||
| Requires-Dist: timelyOSC>=4 | ||
@@ -27,2 +38,3 @@ # pym2149 | ||
| python3 -m venv venvname | ||
| venvname/bin/pip install -U pip | ||
| venvname/bin/pip install pym2149 | ||
@@ -34,8 +46,5 @@ . venvname/bin/activate | ||
| ``` | ||
| # GitHub trick to download some files to play: | ||
| svn export https://github.com/combatopera/pym2149/trunk/contrib | ||
| # Play a tune written in the Lurlene live coding language: | ||
| lc2portaudio 'contrib/Jochen Hippel - 7 Gates of Jambala Level 9.py' | ||
| lc2jack 'contrib/Jochen Hippel - 7 Gates of Jambala Level 9.py' | ||
| lc2portaudio 'contrib/Jochen Hippel - 7 Gates of Jambala Level 9.py' | ||
@@ -42,0 +51,0 @@ # Play a Dosound sound effect: |
@@ -1,9 +0,10 @@ | ||
| aridity>=48 | ||
| diapyr>=18 | ||
| aridity>=78 | ||
| diapyr>=26 | ||
| lagoon>=31 | ||
| Lurlene>=13 | ||
| minBlepy>=13 | ||
| minBlepy>=16 | ||
| numpy>=2.0.2 | ||
| outjack>=15 | ||
| pyrbo>=5 | ||
| pyrbo>=13 | ||
| splut>=4 | ||
| timelyOSC>=4 |
@@ -16,3 +16,2 @@ COPYING | ||
| pym2149/iface.py | ||
| pym2149/jackclient.py | ||
| pym2149/lfsr.py | ||
@@ -28,5 +27,3 @@ pym2149/lha.py | ||
| pym2149/pitch.py | ||
| pym2149/portaudioclient.py | ||
| pym2149/power.py | ||
| pym2149/realtime.arid | ||
| pym2149/reg.py | ||
@@ -78,2 +75,5 @@ pym2149/resid.py | ||
| pym2149/buf_turbo/putstrided_float32ETint16ETuint8.pyxbld | ||
| pym2149/client/__init__.py | ||
| pym2149/client/jack.py | ||
| pym2149/client/portaudio.py | ||
| pym2149/native/__init__.py | ||
@@ -80,0 +80,0 @@ pym2149/native/calsa.c |
@@ -8,13 +8,2 @@ # cython: language_level=3 | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def copyasprefix_uint8(self, np.uint32_t endframe, that): | ||
| cdef np.ndarray[np.uint8_t] py_self_buf = self.buf | ||
| cdef np.uint8_t* self_buf = &py_self_buf[0] | ||
| cdef np.ndarray[np.uint8_t] py_that_buf = that.buf | ||
| cdef np.uint8_t* that_buf = &py_that_buf[0] | ||
| cdef np.uint32_t i | ||
| for i in range(endframe): | ||
| self_buf[i] = that_buf[i] | ||
| @cython.boundscheck(False) | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def copyasprefix_float32(self, np.uint32_t endframe, that): | ||
@@ -39,1 +28,12 @@ cdef np.ndarray[np.float32_t] py_self_buf = self.buf | ||
| self_buf[i] = that_buf[i] | ||
| @cython.boundscheck(False) | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def copyasprefix_uint8(self, np.uint32_t endframe, that): | ||
| cdef np.ndarray[np.uint8_t] py_self_buf = self.buf | ||
| cdef np.uint8_t* self_buf = &py_self_buf[0] | ||
| cdef np.ndarray[np.uint8_t] py_that_buf = that.buf | ||
| cdef np.uint8_t* that_buf = &py_that_buf[0] | ||
| cdef np.uint32_t i | ||
| for i in range(endframe): | ||
| self_buf[i] = that_buf[i] |
@@ -8,14 +8,2 @@ # cython: language_level=3 | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def copywindow_uint8(self, that, np.uint32_t startframe, np.uint32_t endframe): | ||
| cdef np.ndarray[np.uint8_t] py_self_buf = self.buf | ||
| cdef np.uint8_t* self_buf = &py_self_buf[0] | ||
| cdef np.ndarray[np.uint8_t] py_that_buf = that.buf | ||
| cdef np.uint8_t* that_buf = &py_that_buf[0] | ||
| cdef np.uint32_t i | ||
| for i in range(endframe - startframe): | ||
| self_buf[i] = that_buf[startframe] | ||
| startframe += 1 | ||
| @cython.boundscheck(False) | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def copywindow_float32(self, that, np.uint32_t startframe, np.uint32_t endframe): | ||
@@ -42,1 +30,13 @@ cdef np.ndarray[np.float32_t] py_self_buf = self.buf | ||
| startframe += 1 | ||
| @cython.boundscheck(False) | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def copywindow_uint8(self, that, np.uint32_t startframe, np.uint32_t endframe): | ||
| cdef np.ndarray[np.uint8_t] py_self_buf = self.buf | ||
| cdef np.uint8_t* self_buf = &py_self_buf[0] | ||
| cdef np.ndarray[np.uint8_t] py_that_buf = that.buf | ||
| cdef np.uint8_t* that_buf = &py_that_buf[0] | ||
| cdef np.uint32_t i | ||
| for i in range(endframe - startframe): | ||
| self_buf[i] = that_buf[startframe] | ||
| startframe += 1 |
@@ -8,13 +8,2 @@ # cython: language_level=3 | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def fill_i1_uint8(self, np.int8_t value): | ||
| cdef np.ndarray[np.uint8_t] py_self_buf = self.buf | ||
| cdef np.uint8_t* self_buf = &py_self_buf[0] | ||
| cdef np.uint8_t v | ||
| cdef np.uint32_t i | ||
| v = value # Cast once. | ||
| for i in range(py_self_buf.size): | ||
| self_buf[i] = v | ||
| @cython.boundscheck(False) | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def fill_i1_float32(self, np.int8_t value): | ||
@@ -39,1 +28,12 @@ cdef np.ndarray[np.float32_t] py_self_buf = self.buf | ||
| self_buf[i] = v | ||
| @cython.boundscheck(False) | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def fill_i1_uint8(self, np.int8_t value): | ||
| cdef np.ndarray[np.uint8_t] py_self_buf = self.buf | ||
| cdef np.uint8_t* self_buf = &py_self_buf[0] | ||
| cdef np.uint8_t v | ||
| cdef np.uint32_t i | ||
| v = value # Cast once. | ||
| for i in range(py_self_buf.size): | ||
| self_buf[i] = v |
@@ -8,11 +8,2 @@ # cython: language_level=3 | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def fill_same_uint8(self, np.uint8_t value): | ||
| cdef np.ndarray[np.uint8_t] py_self_buf = self.buf | ||
| cdef np.uint8_t* self_buf = &py_self_buf[0] | ||
| cdef np.uint32_t i | ||
| for i in range(py_self_buf.size): | ||
| self_buf[i] = value | ||
| @cython.boundscheck(False) | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def fill_same_float32(self, np.float32_t value): | ||
@@ -33,1 +24,10 @@ cdef np.ndarray[np.float32_t] py_self_buf = self.buf | ||
| self_buf[i] = value | ||
| @cython.boundscheck(False) | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def fill_same_uint8(self, np.uint8_t value): | ||
| cdef np.ndarray[np.uint8_t] py_self_buf = self.buf | ||
| cdef np.uint8_t* self_buf = &py_self_buf[0] | ||
| cdef np.uint32_t i | ||
| for i in range(py_self_buf.size): | ||
| self_buf[i] = value |
@@ -8,11 +8,2 @@ # cython: language_level=3 | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def fillpart_uint8(self, np.uint32_t startframe, np.uint32_t endframe, np.uint8_t value): | ||
| cdef np.ndarray[np.uint8_t] py_self_buf = self.buf | ||
| cdef np.uint8_t* self_buf = &py_self_buf[0] | ||
| while startframe < endframe: | ||
| self_buf[startframe] = value | ||
| startframe += 1 | ||
| @cython.boundscheck(False) | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def fillpart_float32(self, np.uint32_t startframe, np.uint32_t endframe, np.float32_t value): | ||
@@ -33,1 +24,10 @@ cdef np.ndarray[np.float32_t] py_self_buf = self.buf | ||
| startframe += 1 | ||
| @cython.boundscheck(False) | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def fillpart_uint8(self, np.uint32_t startframe, np.uint32_t endframe, np.uint8_t value): | ||
| cdef np.ndarray[np.uint8_t] py_self_buf = self.buf | ||
| cdef np.uint8_t* self_buf = &py_self_buf[0] | ||
| while startframe < endframe: | ||
| self_buf[startframe] = value | ||
| startframe += 1 |
@@ -8,14 +8,2 @@ # cython: language_level=3 | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def mapbuf_uint8(self, that, np.ndarray[np.uint8_t] py_lookup): | ||
| cdef np.ndarray[np.uint8_t] py_self_buf = self.buf | ||
| cdef np.uint8_t* self_buf = &py_self_buf[0] | ||
| cdef np.ndarray[np.uint8_t] py_that_buf = that.buf | ||
| cdef np.uint8_t* that_buf = &py_that_buf[0] | ||
| cdef np.uint8_t* lookup = &py_lookup[0] | ||
| cdef np.uint32_t i | ||
| for i in range(py_that_buf.size): | ||
| self_buf[i] = lookup[that_buf[i]] | ||
| @cython.boundscheck(False) | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def mapbuf_float32(self, that, np.ndarray[np.float32_t] py_lookup): | ||
@@ -42,1 +30,13 @@ cdef np.ndarray[np.float32_t] py_self_buf = self.buf | ||
| self_buf[i] = lookup[that_buf[i]] | ||
| @cython.boundscheck(False) | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def mapbuf_uint8(self, that, np.ndarray[np.uint8_t] py_lookup): | ||
| cdef np.ndarray[np.uint8_t] py_self_buf = self.buf | ||
| cdef np.uint8_t* self_buf = &py_self_buf[0] | ||
| cdef np.ndarray[np.uint8_t] py_that_buf = that.buf | ||
| cdef np.uint8_t* that_buf = &py_that_buf[0] | ||
| cdef np.uint8_t* lookup = &py_lookup[0] | ||
| cdef np.uint32_t i | ||
| for i in range(py_that_buf.size): | ||
| self_buf[i] = lookup[that_buf[i]] |
@@ -8,13 +8,2 @@ # cython: language_level=3 | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def partcopyintonp_uint8(self, np.uint32_t startframe, np.uint32_t endframe, np.ndarray[np.uint8_t] py_thatnp): | ||
| cdef np.ndarray[np.uint8_t] py_self_buf = self.buf | ||
| cdef np.uint8_t* self_buf = &py_self_buf[0] | ||
| cdef np.uint8_t* thatnp = &py_thatnp[0] | ||
| cdef np.uint32_t j | ||
| for j in range(endframe - startframe): | ||
| thatnp[j] = self_buf[startframe] | ||
| startframe += 1 | ||
| @cython.boundscheck(False) | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def partcopyintonp_float32(self, np.uint32_t startframe, np.uint32_t endframe, np.ndarray[np.float32_t] py_thatnp): | ||
@@ -39,1 +28,12 @@ cdef np.ndarray[np.float32_t] py_self_buf = self.buf | ||
| startframe += 1 | ||
| @cython.boundscheck(False) | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def partcopyintonp_uint8(self, np.uint32_t startframe, np.uint32_t endframe, np.ndarray[np.uint8_t] py_thatnp): | ||
| cdef np.ndarray[np.uint8_t] py_self_buf = self.buf | ||
| cdef np.uint8_t* self_buf = &py_self_buf[0] | ||
| cdef np.uint8_t* thatnp = &py_thatnp[0] | ||
| cdef np.uint32_t j | ||
| for j in range(endframe - startframe): | ||
| thatnp[j] = self_buf[startframe] | ||
| startframe += 1 |
@@ -8,6 +8,6 @@ # cython: language_level=3 | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def putstrided_uint8(self, np.uint32_t start, np.uint32_t end, np.uint32_t step, np.ndarray[np.uint8_t] py_data): | ||
| cdef np.ndarray[np.uint8_t] py_self_buf = self.buf | ||
| cdef np.uint8_t* self_buf = &py_self_buf[0] | ||
| cdef np.uint8_t* data = &py_data[0] | ||
| def putstrided_float32(self, np.uint32_t start, np.uint32_t end, np.uint32_t step, np.ndarray[np.float32_t] py_data): | ||
| cdef np.ndarray[np.float32_t] py_self_buf = self.buf | ||
| cdef np.float32_t* self_buf = &py_self_buf[0] | ||
| cdef np.float32_t* data = &py_data[0] | ||
| cdef np.uint32_t j | ||
@@ -22,6 +22,6 @@ j = 0 | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def putstrided_float32(self, np.uint32_t start, np.uint32_t end, np.uint32_t step, np.ndarray[np.float32_t] py_data): | ||
| cdef np.ndarray[np.float32_t] py_self_buf = self.buf | ||
| cdef np.float32_t* self_buf = &py_self_buf[0] | ||
| cdef np.float32_t* data = &py_data[0] | ||
| def putstrided_int16(self, np.uint32_t start, np.uint32_t end, np.uint32_t step, np.ndarray[np.int16_t] py_data): | ||
| cdef np.ndarray[np.int16_t] py_self_buf = self.buf | ||
| cdef np.int16_t* self_buf = &py_self_buf[0] | ||
| cdef np.int16_t* data = &py_data[0] | ||
| cdef np.uint32_t j | ||
@@ -36,6 +36,6 @@ j = 0 | ||
| @cython.cdivision(True) # Don't check for divide-by-zero. | ||
| def putstrided_int16(self, np.uint32_t start, np.uint32_t end, np.uint32_t step, np.ndarray[np.int16_t] py_data): | ||
| cdef np.ndarray[np.int16_t] py_self_buf = self.buf | ||
| cdef np.int16_t* self_buf = &py_self_buf[0] | ||
| cdef np.int16_t* data = &py_data[0] | ||
| def putstrided_uint8(self, np.uint32_t start, np.uint32_t end, np.uint32_t step, np.ndarray[np.uint8_t] py_data): | ||
| cdef np.ndarray[np.uint8_t] py_self_buf = self.buf | ||
| cdef np.uint8_t* self_buf = &py_self_buf[0] | ||
| cdef np.uint8_t* data = &py_data[0] | ||
| cdef np.uint32_t j | ||
@@ -42,0 +42,0 @@ j = 0 |
+28
-42
@@ -22,6 +22,5 @@ # Copyright 2014, 2018, 2019, 2020 Andrzej Cichocki | ||
| from aridity.config import ConfigCtrl | ||
| from aridity.model import wrap | ||
| from aridity.model import Boolean, Resource, wrap | ||
| from diapyr import DI, types, UnsatisfiableRequestException | ||
| from importlib import import_module | ||
| from pathlib import Path | ||
| from io import StringIO | ||
| import logging, sys | ||
@@ -33,4 +32,2 @@ | ||
| namespace = 'pym2149' | ||
| def __init__(self, *params, args = sys.argv[1:], name = 'root'): | ||
@@ -43,15 +40,12 @@ parser = ArgumentParser() | ||
| self.additems = parser.parse_args(args) | ||
| self.path = Path(__file__).resolve().parent / f"{name}.arid" | ||
| self.resource = Resource(__name__, f"{name}.arid") | ||
| @types(DI, this = Config) | ||
| def loadconfig(self, di): | ||
| config = ConfigCtrl() | ||
| config.put('enter', function = enter) | ||
| config.put('py', function = lambda *args: py(getattr(config.node, self.namespace), *args)) | ||
| config.put('resolve', function = lambda *args: AsScope.resolve(di, *args)) | ||
| config.printf("cwd = %s", self.path.parent) | ||
| config.printf("%s . %s", self.namespace, self.path.name) | ||
| cc = ConfigCtrl() | ||
| config = cc._loadappconfig('pym2149', self.resource) | ||
| config.diref = DIRef(di) | ||
| if not self.additems.ignore_settings: | ||
| try: | ||
| config.loadsettings() | ||
| cc.loadsettings() | ||
| except FileNotFoundError as e: | ||
@@ -61,39 +55,31 @@ log.warning("Settings not found: %s", e) | ||
| if 'config' == name: | ||
| with config.repl() as repl: | ||
| for text in value: | ||
| repl.printf("%s", self.namespace) | ||
| for line in text.splitlines(): | ||
| repl(f"\t{line}") | ||
| for text in value: | ||
| (-config).load(StringIO(text)) | ||
| else: | ||
| setattr(getattr(config.node, self.namespace), name, value) | ||
| return getattr(config.node, self.namespace) | ||
| setattr(config, name, value) | ||
| return config | ||
| class AsScope: | ||
| class DIRef: | ||
| @classmethod | ||
| def resolve(cls, di, scope, resolvable): | ||
| def __init__(self, di): | ||
| self.di = di | ||
| def __call__(self, scope, resolvable): | ||
| try: | ||
| return cls(scope, di(_getglobal(scope, resolvable).scalar)) | ||
| return wrap(self.di(resolvable.resolve(scope).scalar)) | ||
| except UnsatisfiableRequestException: | ||
| raise NoSuchPathException | ||
| def __init__(self, parent, obj): | ||
| self.parent = parent | ||
| self.obj = obj | ||
| def isvalue(scope, resolvable): | ||
| try: | ||
| resolvable.resolve(scope) | ||
| val = True | ||
| except NoSuchPathException: | ||
| val = False | ||
| return Boolean(val) | ||
| def resolved(self, name): | ||
| try: | ||
| return wrap(getattr(self.obj, name)) | ||
| except AttributeError: | ||
| return self.parent.resolved(name) | ||
| def pyattr(scope, objresolvable, attrresolvable): | ||
| return wrap(getattr(objresolvable.resolve(scope).scalar, attrresolvable.resolve(scope).cat())) | ||
| def _getglobal(scope, resolvable): | ||
| spec = resolvable.resolve(scope).cat() | ||
| lastdot = spec.rindex('.') | ||
| return wrap(getattr(import_module(spec[:lastdot], __package__), spec[lastdot + 1:])) | ||
| def enter(scope, scoperesolvable, resolvable): | ||
| return resolvable.resolve(scoperesolvable.resolve(scope)) | ||
| def py(config, scope, *clauses): | ||
| return wrap(eval(' '.join(c.cat() for c in clauses), dict(config = config))) | ||
| def py(scope, coderesolvable): | ||
| return wrap(eval(coderesolvable.resolve(scope).cat(), {})) |
+1
-2
@@ -18,3 +18,2 @@ # Copyright 2014, 2018, 2019, 2020 Andrzej Cichocki | ||
| from minBlepy.const import u4 | ||
| import numpy as np | ||
@@ -24,5 +23,5 @@ | ||
| u1 = np.uint8 | ||
| u4 = u4 | ||
| u4 = np.uint32 | ||
| u8 = np.uint64 | ||
| i4 = np.int32 | ||
| i8 = np.int64 |
+3
-16
@@ -29,2 +29,3 @@ # Copyright 2014, 2018, 2019, 2020 Andrzej Cichocki | ||
| from diapyr.util import singleton | ||
| from minBlepy.minblep import Translator | ||
| import logging, numpy as np | ||
@@ -123,16 +124,2 @@ | ||
| class Translator: # TODO: Convert to Node. | ||
| naivex = 0 | ||
| def __init__(self, clockinfo, minbleps): | ||
| self.naiverate = clockinfo.implclock | ||
| self.minbleps = minbleps | ||
| def step(self, framecount): | ||
| naivex = self.naivex | ||
| outcount = self.minbleps.getoutcount(naivex, framecount) | ||
| self.naivex = (naivex + framecount) % self.naiverate | ||
| return naivex, outcount | ||
| class WavBuf(Node): | ||
@@ -156,3 +143,3 @@ | ||
| self.carrybuf = BufType.float().ensureandcrop(self.overflowsize) | ||
| self.translator = Translator(clockinfo, minbleps) | ||
| self.translator = Translator(clockinfo.implclock, minbleps) | ||
| self.dc = floatdtype(0) # Last naive value of previous block. | ||
@@ -175,3 +162,3 @@ self.carrybuf.fill_same(self.dc) # Initial carry can be the initial dc level. | ||
| outbuf.fillpart(self.overflowsize, outsize, self.dc) | ||
| self.minbleps.paste(naivex, diffbuf, outbuf) | ||
| self.minbleps.paste(naivex, diffbuf.buf, outbuf.buf) | ||
| self.carrybuf.copywindow(outbuf, outcount, outsize) | ||
@@ -178,0 +165,0 @@ self.dc = naivebuf.last() |
+3
-2
@@ -25,6 +25,7 @@ # Copyright 2014, 2018, 2019, 2020 Andrzej Cichocki | ||
| from .nod import Node | ||
| from .out import FloatStream, Translator | ||
| from .out import FloatStream | ||
| from .reg import Reg, regproperty | ||
| from diapyr import types | ||
| from lurlene import topitch | ||
| from minBlepy.minblep import Translator | ||
@@ -109,3 +110,3 @@ PAL = 4.43361875e6 * 4 / 18 | ||
| super().__init__() | ||
| self.translator = Translator(clockinfo, minbleps) | ||
| self.translator = Translator(clockinfo.implclock, minbleps) | ||
| self.shortmaster = BufType.short() | ||
@@ -112,0 +113,0 @@ self.outmaster = BufType.float() |
@@ -20,3 +20,3 @@ # Copyright 2014, 2018, 2019, 2020 Andrzej Cichocki | ||
| from . import boot, srcbytecodefactory | ||
| from .. import jackclient | ||
| from ..client import jack | ||
| from ..config import ConfigName | ||
@@ -33,3 +33,3 @@ from ..timerimpl import SyncTimer | ||
| di.add(srcbytecodefactory) | ||
| jackclient.configure(di) | ||
| jack.configure(di) | ||
| di.add(SyncTimer) | ||
@@ -36,0 +36,0 @@ di.add(PhysicalBundle) |
@@ -20,3 +20,3 @@ # Copyright 2014, 2018, 2019, 2020 Andrzej Cichocki | ||
| from . import boot | ||
| from .. import jackclient | ||
| from ..client import jack | ||
| from ..config import ConfigName | ||
@@ -39,3 +39,3 @@ from ..lurlene import loadcontext, LurleneBridge | ||
| di.add(LogicalBundle) | ||
| jackclient.configure(di) | ||
| jack.configure(di) | ||
| di.add(Player) | ||
@@ -42,0 +42,0 @@ di.all(Started) |
@@ -20,3 +20,3 @@ # Copyright 2014, 2018, 2019, 2020 Andrzej Cichocki | ||
| from . import boot | ||
| from .. import portaudioclient | ||
| from ..client import portaudio | ||
| from ..config import ConfigName | ||
@@ -39,3 +39,3 @@ from ..lurlene import loadcontext, LurleneBridge | ||
| di.add(LogicalBundle) | ||
| portaudioclient.configure(di) | ||
| portaudio.configure(di) | ||
| di.add(Player) | ||
@@ -42,0 +42,0 @@ di.all(Started) |
@@ -20,3 +20,3 @@ # Copyright 2014, 2018, 2019, 2020 Andrzej Cichocki | ||
| from . import boot | ||
| from .. import jackclient | ||
| from ..client import jack | ||
| from ..config import ConfigName | ||
@@ -34,3 +34,3 @@ from ..timerimpl import SyncTimer | ||
| di.add(YMOpen) | ||
| jackclient.configure(di) | ||
| jack.configure(di) | ||
| di.add(SyncTimer) | ||
@@ -37,0 +37,0 @@ di.add(PhysicalBundle) |
@@ -20,3 +20,3 @@ # Copyright 2014, 2018, 2019, 2020 Andrzej Cichocki | ||
| from . import boot | ||
| from .. import portaudioclient | ||
| from ..client import portaudio | ||
| from ..config import ConfigName | ||
@@ -34,3 +34,3 @@ from ..timerimpl import SyncTimer | ||
| di.add(YMOpen) | ||
| portaudioclient.configure(di) | ||
| portaudio.configure(di) | ||
| di.add(SyncTimer) | ||
@@ -37,0 +37,0 @@ di.add(PhysicalBundle) |
@@ -19,3 +19,3 @@ # Copyright 2014, 2018, 2019, 2020 Andrzej Cichocki | ||
| from .const import u4 | ||
| from minBlepy.shapes import floatdtype | ||
| from minBlepy import floatdtype | ||
| import math, numpy as np | ||
@@ -22,0 +22,0 @@ |
+1
-1
| [build-system] | ||
| requires = ["setuptools", "wheel", "Cython<3", "numpy"] | ||
| requires = ["setuptools", "wheel", "Cython==3.0.11", "numpy==2.0.2"] |
+2
-4
@@ -18,2 +18,3 @@ # pym2149 | ||
| python3 -m venv venvname | ||
| venvname/bin/pip install -U pip | ||
| venvname/bin/pip install pym2149 | ||
@@ -25,8 +26,5 @@ . venvname/bin/activate | ||
| ``` | ||
| # GitHub trick to download some files to play: | ||
| svn export https://github.com/combatopera/pym2149/trunk/contrib | ||
| # Play a tune written in the Lurlene live coding language: | ||
| lc2portaudio 'contrib/Jochen Hippel - 7 Gates of Jambala Level 9.py' | ||
| lc2jack 'contrib/Jochen Hippel - 7 Gates of Jambala Level 9.py' | ||
| lc2portaudio 'contrib/Jochen Hippel - 7 Gates of Jambala Level 9.py' | ||
@@ -33,0 +31,0 @@ # Play a Dosound sound effect: |
+32
-72
@@ -1,2 +0,2 @@ | ||
| import setuptools | ||
| from setuptools import setup | ||
@@ -11,4 +11,2 @@ def long_description(): | ||
| suffixes = '.pyx', '.c' | ||
| def __init__(self, module, path): | ||
@@ -18,9 +16,5 @@ self.module = module | ||
| def buildrequires(self): | ||
| if self.path.endswith('.pyx'): | ||
| yield 'Cython<3' | ||
| def make_ext(self): | ||
| g = {} | ||
| with open(self.path + 'bld') as f: # Assume project root. | ||
| with open("%sbld" % self.path) as f: # Assume project root. | ||
| exec(f.read(), g) | ||
@@ -30,73 +24,39 @@ return g['make_ext'](self.module, self.path) | ||
| def __init__(self, rootdir): | ||
| import os, setuptools, subprocess | ||
| self.packages = setuptools.find_packages(rootdir) | ||
| def addextpaths(dirpath, moduleprefix, suffix = '.pyx'): | ||
| for name in sorted(os.listdir(os.path.join(rootdir, dirpath))): | ||
| if name.endswith(suffix): | ||
| module = "%s%s" % (moduleprefix, name[:-len(suffix)]) | ||
| if module not in extpaths: | ||
| extpaths[module] = self.PYXPath(module, os.path.join(dirpath, name)) | ||
| from setuptools import find_packages | ||
| import os | ||
| self.packages = find_packages(rootdir) | ||
| extpaths = {} | ||
| def addextpaths(dirpath, moduleprefix): | ||
| names = sorted(os.listdir(os.path.join(rootdir, dirpath))) | ||
| for suffix in self.PYXPath.suffixes: | ||
| for name in names: | ||
| if name.endswith(suffix): | ||
| module = "%s%s" % (moduleprefix, name[:-len(suffix)]) | ||
| if module not in extpaths: | ||
| extpaths[module] = self.PYXPath(module, os.path.join(dirpath, name)) | ||
| addextpaths('.', '') | ||
| for package in self.packages: | ||
| addextpaths(package.replace('.', os.sep), "%s." % package) | ||
| extpaths = extpaths.values() | ||
| if extpaths and os.path.isdir(os.path.join(rootdir, '.git')): # We could be an unpacked sdist. | ||
| check_ignore = subprocess.Popen(['git', 'check-ignore'] + [p.path for p in extpaths], cwd = rootdir, stdout = subprocess.PIPE) | ||
| ignoredpaths = set(check_ignore.communicate()[0].decode().splitlines()) | ||
| assert check_ignore.wait() in [0, 1] | ||
| self.extpaths = [path for path in extpaths if path.path not in ignoredpaths] | ||
| else: | ||
| self.extpaths = extpaths | ||
| self.extpaths = extpaths.values() | ||
| def lazy(clazz, init, *initbefore): | ||
| from threading import Lock | ||
| initlock = Lock() | ||
| init = [init] | ||
| def overridefactory(name): | ||
| orig = getattr(clazz, name) | ||
| def override(*args, **kwargs): | ||
| with initlock: | ||
| if init: | ||
| init[0](obj) | ||
| del init[:] | ||
| return orig(*args, **kwargs) | ||
| return override | ||
| Lazy = type('Lazy', (clazz, object), {name: overridefactory(name) for name in initbefore}) | ||
| obj = Lazy() | ||
| return obj | ||
| # FIXME: The idea was to defer anything Cython/numpy to pyximport time, but this doesn't achieve that. | ||
| def cythonize(extensions): | ||
| def init(ext_modules): | ||
| ordinary = [] | ||
| cythonizable = [] | ||
| for e in extensions: | ||
| (cythonizable if any(s.endswith('.pyx') for s in e.sources) else ordinary).append(e) | ||
| if cythonizable: | ||
| def setup_kwargs(self): | ||
| kwargs = dict(packages = self.packages) | ||
| if self.extpaths: | ||
| from Cython.Build import cythonize | ||
| ordinary += cythonize(cythonizable) | ||
| ext_modules[:] = ordinary | ||
| return lazy(list, init, '__getitem__', '__iter__', '__len__') | ||
| kwargs['ext_modules'] = cythonize([path.make_ext() for path in self.extpaths]) | ||
| return kwargs | ||
| def ext_modules(): | ||
| extensions = [path.make_ext() for path in sourceinfo.extpaths] | ||
| return dict(ext_modules = cythonize(extensions)) if extensions else {} | ||
| sourceinfo = SourceInfo('.') | ||
| setuptools.setup( | ||
| name = 'pym2149', | ||
| version = '33', | ||
| description = 'YM2149 emulator supporting YM files, OSC to JACK, PortAudio, WAV', | ||
| long_description = long_description(), | ||
| long_description_content_type = 'text/markdown', | ||
| url = 'https://github.com/combatopera/pym2149', | ||
| author = 'Andrzej Cichocki', | ||
| packages = sourceinfo.packages, | ||
| py_modules = [], | ||
| install_requires = ['aridity>=48', 'diapyr>=18', 'lagoon>=31', 'Lurlene>=13', 'minBlepy>=13', 'outjack>=15', 'pyrbo>=5', 'splut>=4', 'timelyOSC>=4'], | ||
| package_data = {'': ['*.pxd', '*.pyx', '*.pyxbld', '*.arid', '*.aridt']}, | ||
| entry_points = {'console_scripts': ['bpmtool=pym2149.scripts.bpmtool:main', 'dosound2jack=pym2149.scripts.dosound2jack:main', 'dosound2txt=pym2149.scripts.dosound2txt:main', 'dosound2wav=pym2149.scripts.dosound2wav:main', 'dsd2wav=pym2149.scripts.dsd2wav:main', 'lc2jack=pym2149.scripts.lc2jack:main', 'lc2portaudio=pym2149.scripts.lc2portaudio:main', 'lc2txt=pym2149.scripts.lc2txt:main', 'lc2wav=pym2149.scripts.lc2wav:main', 'ym2jack=pym2149.scripts.ym2jack:main', 'ym2portaudio=pym2149.scripts.ym2portaudio:main', 'ym2txt=pym2149.scripts.ym2txt:main', 'ym2wav=pym2149.scripts.ym2wav:main', 'mkdsd=ymtests.mkdsd:main']}, | ||
| **ext_modules()) | ||
| setup( | ||
| name = 'pym2149', | ||
| version = '34', | ||
| description = 'YM2149 emulator supporting YM files, OSC to JACK, PortAudio, WAV', | ||
| long_description = long_description(), | ||
| long_description_content_type = 'text/markdown', | ||
| url = 'https://github.com/combatopera/pym2149', | ||
| author = 'Andrzej Cichocki', | ||
| author_email = '3613868+combatopera@users.noreply.github.com', | ||
| py_modules = [], | ||
| install_requires = ['aridity>=78', 'diapyr>=26', 'lagoon>=31', 'Lurlene>=13', 'minBlepy>=16', 'numpy>=2.0.2', 'outjack>=15', 'pyrbo>=13', 'splut>=4', 'timelyOSC>=4'], | ||
| package_data = {'': ['*.pxd', '*.pyx', '*.pyxbld', '*.arid', '*.aridt']}, | ||
| entry_points = {'console_scripts': ['bpmtool=pym2149.scripts.bpmtool:main', 'dosound2jack=pym2149.scripts.dosound2jack:main', 'dosound2txt=pym2149.scripts.dosound2txt:main', 'dosound2wav=pym2149.scripts.dosound2wav:main', 'dsd2wav=pym2149.scripts.dsd2wav:main', 'lc2jack=pym2149.scripts.lc2jack:main', 'lc2portaudio=pym2149.scripts.lc2portaudio:main', 'lc2txt=pym2149.scripts.lc2txt:main', 'lc2wav=pym2149.scripts.lc2wav:main', 'ym2jack=pym2149.scripts.ym2jack:main', 'ym2portaudio=pym2149.scripts.ym2portaudio:main', 'ym2txt=pym2149.scripts.ym2txt:main', 'ym2wav=pym2149.scripts.ym2wav:main', 'mkdsd=ymtests.mkdsd:main']}, | ||
| **sourceinfo.setup_kwargs(), | ||
| ) |
| # Copyright 2014, 2018, 2019, 2020 Andrzej Cichocki | ||
| # This file is part of pym2149. | ||
| # | ||
| # pym2149 is free software: you can redistribute it and/or modify | ||
| # it under the terms of the GNU General Public License as published by | ||
| # the Free Software Foundation, either version 3 of the License, or | ||
| # (at your option) any later version. | ||
| # | ||
| # pym2149 is distributed in the hope that it will be useful, | ||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| # GNU General Public License for more details. | ||
| # | ||
| # You should have received a copy of the GNU General Public License | ||
| # along with pym2149. If not, see <http://www.gnu.org/licenses/>. | ||
| from .const import clientname | ||
| from .iface import AmpScale, Config, Platform, Stream | ||
| from .nod import Node | ||
| from .out import FloatStream, StereoInfo | ||
| from diapyr import types | ||
| import outjack.jackclient as jc, logging | ||
| log = logging.getLogger(__name__) | ||
| class JackClient(jc.JackClient, Platform): | ||
| @types(Config, StereoInfo) | ||
| def __init__(self, config, stereoinfo): | ||
| portcount = stereoinfo.getoutchans.size + config.SID.enabled # FIXME: This is a hack. | ||
| super().__init__(clientname, portcount, config.jackringsize, config.jackcoupling) | ||
| def start(self): | ||
| super().start() | ||
| log.debug( | ||
| "JACK block size: %s or %.3f seconds", | ||
| self.buffersize, | ||
| self.buffersize / self.outputrate) | ||
| class JackStream(Stream, Node, metaclass = AmpScale): | ||
| log2maxpeaktopeak = 1 | ||
| @types(Config, [FloatStream], JackClient) | ||
| def __init__(self, config, streams, client): | ||
| super().__init__() | ||
| self.systemchannelcount = config.systemchannelcount | ||
| for stream in streams: | ||
| for chanindex in range(stream.chancount): | ||
| client.port_register_output(f"{stream.streamname}_{1 + chanindex}") | ||
| self.streams = streams | ||
| self.client = client | ||
| def start(self): | ||
| self.client.activate() | ||
| for stream in self.streams: | ||
| # Connect all system channels, cycling over our streams if necessary: | ||
| for syschanindex in range(self.systemchannelcount): | ||
| chanindex = syschanindex % stream.chancount | ||
| self.client.connect(f"{clientname}:{stream.streamname}_{1 + chanindex}", f"system:playback_{1 + syschanindex}") | ||
| self.filler = BufferFiller(sum(s.chancount for s in self.streams), self.client.buffersize, self.client.current_output_buffer, self.client.send_and_get_output_buffer) | ||
| def callimpl(self): | ||
| self.filler([self.chain(wav) for stream in self.streams for wav in stream]) | ||
| def flush(self): | ||
| pass # Nothing to be done. | ||
| def stop(self): | ||
| self.client.deactivate() | ||
| class BufferFiller: | ||
| def __init__(self, portcount, buffersize, init, flip): | ||
| self.portcount = portcount | ||
| self.buffersize = buffersize | ||
| self._newbuf(init) | ||
| self.flip = flip | ||
| def __call__(self, outbufs): | ||
| n = len(outbufs[0]) | ||
| i = 0 | ||
| while i < n: | ||
| m = min(n - i, self.buffersize - self.cursor) | ||
| for portindex in range(self.portcount): | ||
| self.outbuf[portindex, self.cursor:self.cursor + m] = outbufs[portindex].buf[i:i + m] | ||
| self.cursor += m | ||
| i += m | ||
| if self.cursor == self.buffersize: | ||
| self._newbuf(self.flip) | ||
| def _newbuf(self, factory): | ||
| outbuf = factory().view() | ||
| outbuf.shape = self.portcount, self.buffersize | ||
| self.outbuf = outbuf | ||
| self.cursor = 0 | ||
| def configure(di): | ||
| di.add(JackClient) | ||
| di.add(JackStream) |
| # Copyright 2014, 2018, 2019, 2020 Andrzej Cichocki | ||
| # This file is part of pym2149. | ||
| # | ||
| # pym2149 is free software: you can redistribute it and/or modify | ||
| # it under the terms of the GNU General Public License as published by | ||
| # the Free Software Foundation, either version 3 of the License, or | ||
| # (at your option) any later version. | ||
| # | ||
| # pym2149 is distributed in the hope that it will be useful, | ||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| # GNU General Public License for more details. | ||
| # | ||
| # You should have received a copy of the GNU General Public License | ||
| # along with pym2149. If not, see <http://www.gnu.org/licenses/>. | ||
| from .iface import AmpScale, Config, Platform, Stream | ||
| from .jackclient import BufferFiller | ||
| from .nod import Node | ||
| from .out import FloatStream, StereoInfo | ||
| from diapyr import types | ||
| import logging, outjack.portaudioclient as pac | ||
| log = logging.getLogger(__name__) | ||
| class PortAudioClient(pac.PortAudioClient, Platform): | ||
| @types(Config, StereoInfo) | ||
| def __init__(self, config, stereoinfo): | ||
| config = config.PortAudio | ||
| super().__init__(stereoinfo.getoutchans.size, config.outputrate, config.buffersize, config.ringsize, config.coupling) | ||
| class PortAudioStream(Node, Stream, metaclass = AmpScale): | ||
| log2maxpeaktopeak = 1 | ||
| @types(StereoInfo, FloatStream, PortAudioClient) | ||
| def __init__(self, stereoinfo, wavs, client): | ||
| super().__init__() | ||
| self.chancount = stereoinfo.getoutchans.size | ||
| self.wavs = wavs | ||
| self.client = client | ||
| def start(self): | ||
| self.client.activate() | ||
| self.filler = BufferFiller(self.chancount, self.client.buffersize, self.client.current_output_buffer, self.client.send_and_get_output_buffer) | ||
| def callimpl(self): | ||
| self.filler([self.chain(wav) for wav in self.wavs]) | ||
| def flush(self): | ||
| pass | ||
| def stop(self): | ||
| self.client.deactivate() | ||
| def configure(di): | ||
| di.add(PortAudioClient) | ||
| di.add(PortAudioStream) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
5906023
50.37%4352
-0.93%