silk-python 0.2.7__cp313-cp313-win32.whl

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.
Binary file
@@ -0,0 +1,27 @@
1
+ from typing import Any, BinaryIO
2
+
3
+ class SilkError(Exception):
4
+ def __init__(self, code) -> Any: ...
5
+
6
+ def encode(
7
+ input: BinaryIO,
8
+ output: BinaryIO,
9
+ sample_rate: int,
10
+ bit_rate: int,
11
+ max_internal_sample_rate: int = 24000,
12
+ packet_loss_percentage: int = 0,
13
+ complexity: int = 2,
14
+ use_inband_fec: bool = False,
15
+ use_dtx: bool = False,
16
+ tencent: bool = True,
17
+ ) -> bytes: ...
18
+ def decode(
19
+ input: BinaryIO,
20
+ output: BinaryIO,
21
+ sample_rate: int,
22
+ frame_size: int = 0,
23
+ frames_per_packet: int = 1,
24
+ more_internal_decoder_frames: bool = False,
25
+ in_band_fec_offset: int = 0,
26
+ loss: bool = False,
27
+ ) -> bytes: ...
@@ -0,0 +1,275 @@
1
+ # cython: language_level=3
2
+ # cython: cdivision=True
3
+ from cpython.bytes cimport (PyBytes_AS_STRING, PyBytes_Check,
4
+ PyBytes_FromStringAndSize, PyBytes_Size)
5
+ from cpython.mem cimport PyMem_Free, PyMem_Malloc
6
+ from cpython.object cimport PyObject, PyObject_HasAttrString
7
+ from libc.stdint cimport int16_t, int32_t, uint8_t
8
+
9
+ from pysilk.backends.cython.silk cimport (SHOULD_SWAP,
10
+ SKP_SILK_SDK_DecControlStruct,
11
+ SKP_Silk_SDK_Decode,
12
+ SKP_SILK_SDK_EncControlStruct,
13
+ SKP_Silk_SDK_Encode,
14
+ SKP_Silk_SDK_Get_Decoder_Size,
15
+ SKP_Silk_SDK_Get_Encoder_Size,
16
+ SKP_Silk_SDK_InitDecoder,
17
+ SKP_Silk_SDK_InitEncoder, swap_i16)
18
+
19
+
20
+ class SilkError(Exception):
21
+ def __init__(self, code):
22
+ self.code = code
23
+
24
+ def __str__(self):
25
+ if isinstance(self.code, int):
26
+ if self.code == -1:
27
+ return "ENC_INPUT_INVALID_NO_OF_SAMPLES"
28
+ elif self.code == -2:
29
+ return "ENC_FS_NOT_SUPPORTED"
30
+ elif self.code == -3:
31
+ return "ENC_PACKET_SIZE_NOT_SUPPORTED"
32
+ elif self.code == -4:
33
+ return "ENC_PAYLOAD_BUF_TOO_SHORT"
34
+ elif self.code == -5:
35
+ return "ENC_INVALID_LOSS_RATE"
36
+ elif self.code == -6:
37
+ return "ENC_INVALID_COMPLEXITY_SETTING"
38
+ elif self.code == -7:
39
+ return "ENC_INVALID_INBAND_FEC_SETTING"
40
+ elif self.code == -8:
41
+ return "ENC_INVALID_DTX_SETTING"
42
+ elif self.code == -9:
43
+ return "ENC_INTERNAL_ERROR"
44
+ elif self.code == -10:
45
+ return "DEC_INVALID_SAMPLING_FREQUENCY"
46
+ elif self.code == -11:
47
+ return "DEC_PAYLOAD_TOO_LARGE"
48
+ elif self.code == -12:
49
+ return "DEC_PAYLOAD_ERROR"
50
+ else:
51
+ return "Other error"
52
+ else:
53
+ return str(self.code)
54
+
55
+
56
+ cdef inline bytes i16_to_bytes(int16_t data):
57
+ cdef:
58
+ uint8_t * p = <uint8_t *> &data
59
+ bytes bt = PyBytes_FromStringAndSize(NULL, 2)
60
+ if <PyObject*>bt == NULL:
61
+ raise MemoryError
62
+ cdef uint8_t* buf = <uint8_t*>PyBytes_AS_STRING(bt)
63
+ buf[0] = p[0]
64
+ buf[1] = p[1]
65
+ return bt
66
+
67
+ cdef inline int16_t bytes_to_i16(bytes data):
68
+ cdef int16_t buf = 0
69
+ cdef uint8_t *p = <uint8_t *> &buf
70
+ p[0] = <uint8_t> data[0]
71
+ p[1] = <uint8_t> data[1]
72
+ return buf
73
+
74
+ cdef inline void write_i16_le(object output, int16_t data):
75
+ if SHOULD_SWAP:
76
+ data = swap_i16(data)
77
+ output.write(i16_to_bytes(data))
78
+
79
+ cdef inline int16_t read_i16_le(object input):
80
+ chunk = input.read(2) # type: bytes
81
+ cdef int16_t data = bytes_to_i16(chunk)
82
+ if SHOULD_SWAP:
83
+ data = swap_i16(data)
84
+ return data
85
+
86
+ cdef inline uint8_t PyFile_Check(object file):
87
+ if PyObject_HasAttrString(file, "read") and PyObject_HasAttrString(file, "write"): # should we check seek method?
88
+ return 1
89
+ return 0
90
+
91
+ def encode(object input,
92
+ object output,
93
+ int32_t sample_rate,
94
+ int32_t bit_rate,
95
+ int32_t max_internal_sample_rate = 24000,
96
+ int32_t packet_loss_percentage = 0,
97
+ int32_t complexity = 2,
98
+ bint use_inband_fec = False,
99
+ bint use_dtx = False,
100
+ bint tencent = True):
101
+ """encode(input: BinaryIO, output: BinaryIO, sample_rate: int, bit_rate: int, max_internal_sample_rate: int = 24000, packet_loss_percentage: int = 0, complexity: int = 2, use_inband_fec: bool = False, use_dtx: bool = False, tencent: bool = True) -> bytes
102
+
103
+ encode pcm to silk
104
+ :param input: BytesIO or an openfile with "rb" mode
105
+ :param output: BytesIO or an openfile with "wb" mode
106
+ :param sample_rate:
107
+ :param bit_rate:
108
+ :param max_internal_sample_rate:
109
+ :param packet_loss_percentage:
110
+ :param complexity:
111
+ :param use_inband_fec:
112
+ :param use_dtx:
113
+ :param tencent: Tencent's special tag
114
+ :return: None
115
+ """
116
+ if not PyFile_Check(input):
117
+ raise TypeError("input except a file-like object, got %s" % type(input).__name__)
118
+ if not PyFile_Check(output):
119
+ raise TypeError("output except a file-like object, got %s" % type(output).__name__)
120
+
121
+ cdef SKP_SILK_SDK_EncControlStruct enc_control
122
+ enc_control.API_sampleRate = sample_rate
123
+ enc_control.maxInternalSampleRate = max_internal_sample_rate
124
+ enc_control.packetSize = (20 * sample_rate) / 1000
125
+ enc_control.bitRate = bit_rate
126
+ enc_control.packetLossPercentage = packet_loss_percentage
127
+ enc_control.complexity = complexity
128
+ enc_control.useInBandFEC = use_inband_fec
129
+ enc_control.useDTX = use_dtx
130
+
131
+ cdef SKP_SILK_SDK_EncControlStruct enc_status
132
+ enc_status.API_sampleRate = 0
133
+ enc_status.maxInternalSampleRate = 0
134
+ enc_status.packetSize = 0
135
+ enc_status.bitRate = 0
136
+ enc_status.packetLossPercentage = 0
137
+ enc_status.complexity = 0
138
+ enc_status.useInBandFEC = 0
139
+ enc_status.useDTX = 0
140
+
141
+ cdef int32_t enc_size_bytes = 0
142
+ cdef int32_t code = SKP_Silk_SDK_Get_Encoder_Size(&enc_size_bytes)
143
+ if code != 0:
144
+ raise SilkError(code)
145
+ cdef void * enc = PyMem_Malloc(<size_t> enc_size_bytes)
146
+ if enc == NULL:
147
+ raise MemoryError
148
+ code = SKP_Silk_SDK_InitEncoder(enc, &enc_status)
149
+ if code != 0:
150
+ PyMem_Free(enc)
151
+ raise SilkError(code)
152
+ cdef int32_t frame_size = sample_rate / 1000 * 40
153
+ if tencent:
154
+ output.write(b"\x02#!SILK_V3")
155
+ else:
156
+ output.write(b"#!SILK_V3")
157
+ cdef int16_t n_bytes = 1250
158
+ cdef uint8_t payload[1250]
159
+ cdef int16_t* chunk_ptr
160
+ cdef int32_t chunk_size
161
+ try:
162
+ while True:
163
+ chunk = input.read(frame_size) # type: bytes
164
+ if not PyBytes_Check(chunk):
165
+ raise TypeError(f"input must be a file-like rb object, got {type(input).__name__}")
166
+
167
+ n_bytes = 1250
168
+ if <int32_t> PyBytes_Size(chunk) < frame_size:
169
+ break
170
+ chunk_ptr = <int16_t *> PyBytes_AS_STRING(chunk)
171
+ chunk_size = <int32_t> (PyBytes_Size(chunk) / 2)
172
+ with nogil:
173
+ code = SKP_Silk_SDK_Encode(enc,
174
+ &enc_control,
175
+ chunk_ptr,
176
+ chunk_size,
177
+ payload,
178
+ &n_bytes)
179
+ if code != 0:
180
+ raise SilkError(code)
181
+
182
+ write_i16_le(output, n_bytes)
183
+ output.write(<bytes> payload[0:n_bytes])
184
+ finally:
185
+ PyMem_Free(enc)
186
+
187
+ def decode(object input,
188
+ object output,
189
+ int32_t sample_rate,
190
+ int32_t frame_size=0,
191
+ int32_t frames_per_packet=1,
192
+ bint more_internal_decoder_frames=False,
193
+ int32_t in_band_fec_offset=0,
194
+ bint loss=False):
195
+ """decode(input: BinaryIO, output: BinaryIO, sample_rate: int, frame_size: int = 0, frames_per_packet: int = 1, more_internal_decoder_frames: bool = False, in_band_fec_offset: int = 0, loss: bool = False) -> bytes
196
+
197
+ decode silk to pcm
198
+ :param input:
199
+ :param output:
200
+ :param sample_rate:
201
+ :param frame_size:
202
+ :param frames_per_packet:
203
+ :param more_internal_decoder_frames:
204
+ :param in_band_fec_offset:
205
+ :param loss:
206
+ :return:
207
+ """
208
+ if not PyFile_Check(input):
209
+ raise TypeError("input except a file-like object, got %s" % type(input).__name__)
210
+ if not PyFile_Check(output):
211
+ raise TypeError("output except a file-like object, got %s" % type(output).__name__)
212
+
213
+ chunk = input.read(9) # type: bytes
214
+ if not PyBytes_Check(chunk):
215
+ raise TypeError(f"input must be a file-like rb object, got {type(input).__name__}")
216
+ if chunk != b"#!SILK_V3" and chunk != b"\x02#!SILK_V":
217
+ raise SilkError("INVALID")
218
+ elif chunk == b"\x02#!SILK_V":
219
+ chunk = input.read(1)
220
+ if chunk != b"3":
221
+ raise SilkError("INVALID")
222
+
223
+ cdef SKP_SILK_SDK_DecControlStruct dec_control
224
+ dec_control.API_sampleRate = sample_rate
225
+ dec_control.frameSize = frame_size
226
+ dec_control.framesPerPacket = frames_per_packet
227
+ dec_control.moreInternalDecoderFrames = more_internal_decoder_frames
228
+ dec_control.inBandFECOffset = in_band_fec_offset
229
+ cdef int32_t dec_size = 0
230
+ cdef int32_t code = SKP_Silk_SDK_Get_Decoder_Size(&dec_size)
231
+ if code != 0:
232
+ raise SilkError(code)
233
+ cdef void *dec = PyMem_Malloc(dec_size)
234
+ if dec == NULL:
235
+ raise MemoryError
236
+ code = SKP_Silk_SDK_InitDecoder(dec)
237
+ if code != 0:
238
+ PyMem_Free(dec)
239
+ raise SilkError(code)
240
+ frame_size = sample_rate / 1000 * 40
241
+ # cdef uint8_t buf[frame_size] # otherwise need malloc
242
+ cdef uint8_t *buf = <uint8_t *> PyMem_Malloc(frame_size)
243
+ if buf == NULL:
244
+ PyMem_Free(dec)
245
+ raise MemoryError
246
+ cdef int16_t n_bytes
247
+ cdef const uint8_t *chunk_ptr
248
+ try:
249
+ while True:
250
+ chunk = input.read(2)
251
+ if PyBytes_Size(chunk) < 2:
252
+ break
253
+ n_bytes = bytes_to_i16(chunk)
254
+ if SHOULD_SWAP:
255
+ n_bytes = swap_i16(n_bytes)
256
+ if n_bytes > <int16_t> frame_size:
257
+ raise SilkError("INVALID")
258
+ chunk = input.read(n_bytes) # type: bytes
259
+ if <int16_t> PyBytes_Size(chunk) < n_bytes: # not enough data
260
+ raise SilkError("INVALID")
261
+ chunk_ptr = <const uint8_t *> PyBytes_AS_STRING(chunk)
262
+ with nogil:
263
+ code = SKP_Silk_SDK_Decode(dec,
264
+ &dec_control,
265
+ loss,
266
+ chunk_ptr,
267
+ <const int32_t> n_bytes,
268
+ <int16_t *> buf,
269
+ &n_bytes)
270
+ if code != 0:
271
+ raise SilkError(code)
272
+ output.write(<bytes> buf[:n_bytes * 2])
273
+ finally:
274
+ PyMem_Free(buf)
275
+ PyMem_Free(dec)
@@ -0,0 +1,72 @@
1
+ # cython: language_level=3
2
+ # cython: cdivision=True
3
+ from libc.stdint cimport int16_t, int32_t, uint8_t
4
+
5
+
6
+ cdef extern from "SKP_Silk_control.h" nogil:
7
+ ctypedef struct SKP_SILK_SDK_EncControlStruct:
8
+ int32_t API_sampleRate
9
+ int32_t maxInternalSampleRate
10
+ int32_t packetSize
11
+ int32_t bitRate
12
+ int32_t packetLossPercentage
13
+ int32_t complexity
14
+ int32_t useInBandFEC
15
+ int32_t useDTX
16
+ ctypedef struct SKP_SILK_SDK_DecControlStruct:
17
+ int32_t API_sampleRate
18
+ int32_t frameSize
19
+ int32_t framesPerPacket
20
+ int32_t moreInternalDecoderFrames
21
+ int32_t inBandFECOffset
22
+
23
+
24
+ cdef extern from "SKP_Silk_SDK_API.h" nogil:
25
+ int32_t SKP_Silk_SDK_Get_Encoder_Size(int32_t *encSizeBytes)
26
+ int32_t SKP_Silk_SDK_InitEncoder(void *encState, SKP_SILK_SDK_EncControlStruct *encStatus)
27
+ int32_t SKP_Silk_SDK_Encode(void *encState,
28
+ const SKP_SILK_SDK_EncControlStruct *encControl,
29
+ const int16_t *samplesIn,
30
+ int32_t nSamplesIn,
31
+ uint8_t *outData,
32
+ int16_t *nBytesOut)
33
+ int32_t SKP_Silk_SDK_Get_Decoder_Size(int32_t *decSizeBytes)
34
+ int32_t SKP_Silk_SDK_InitDecoder(void *decState)
35
+ int32_t SKP_Silk_SDK_Decode(void * decState,
36
+ SKP_SILK_SDK_DecControlStruct *decControl,
37
+ int32_t lostFlag,
38
+ const uint8_t *inData,
39
+ const int32_t nBytesIn,
40
+ int16_t *samplesOut,
41
+ int16_t *nSamplesOut)
42
+
43
+ cdef extern from * nogil:
44
+ """
45
+ /*
46
+ void swap_i16(int16_t *data)
47
+ {
48
+ int8_t *p = (int8_t *)data;
49
+ int8_t tmp = p[0];
50
+ p[0] = p[1];
51
+ p[1] = tmp;
52
+ }
53
+ */
54
+ uint8_t is_le()
55
+ {
56
+ uint16_t data=1;
57
+ return *(uint8_t*)&data;
58
+ }
59
+ #if defined(_WIN64) || defined(_WIN32)
60
+ #define swap_i16 _byteswap_ushort
61
+ #else
62
+ #define swap_i16 __builtin_bswap16
63
+ #endif /* _WIN32 */
64
+ #ifdef WORDS_BIGENDIAN
65
+ #define SHOULD_SWAP 1
66
+ #else
67
+ #define SHOULD_SWAP 0
68
+ #endif
69
+ """
70
+ int16_t swap_i16(int16_t data)
71
+ uint8_t is_le()
72
+ int SHOULD_SWAP
@@ -0,0 +1,108 @@
1
+ Metadata-Version: 2.4
2
+ Name: silk-python
3
+ Version: 0.2.7
4
+ Summary: silk encode and decode
5
+ Home-page: https://github.com/synodriver/pysilk
6
+ Author: synodriver
7
+ Author-email: diguohuangjiajinweijun@gmail.com
8
+ License: BSD
9
+ Keywords: silk,encode,decode,pcm,audio
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: License :: OSI Approved :: BSD License
13
+ Classifier: Topic :: Multimedia :: Sound/Audio
14
+ Classifier: Programming Language :: C
15
+ Classifier: Programming Language :: Cython
16
+ Classifier: Programming Language :: Python
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: Implementation :: CPython
24
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
25
+ Requires-Python: >=3.6
26
+ Description-Content-Type: text/markdown
27
+ Requires-Dist: cffi>=1.0.0
28
+ Dynamic: author
29
+ Dynamic: author-email
30
+ Dynamic: classifier
31
+ Dynamic: description
32
+ Dynamic: description-content-type
33
+ Dynamic: home-page
34
+ Dynamic: keywords
35
+ Dynamic: license
36
+ Dynamic: requires-dist
37
+ Dynamic: requires-python
38
+ Dynamic: summary
39
+
40
+ <h1 align="center"><i>✨ pysilk ✨ </i></h1>
41
+
42
+ <h3 align="center">The python binding for <a href="https://github.com/kn007/silk-v3-decoder">silk-v3-decoder</a> </h3>
43
+
44
+ [![pypi](https://img.shields.io/pypi/v/silk-python.svg)](https://pypi.org/project/silk-python/)
45
+ ![python](https://img.shields.io/pypi/pyversions/silk-python)
46
+ ![implementation](https://img.shields.io/pypi/implementation/silk-python)
47
+ ![wheel](https://img.shields.io/pypi/wheel/silk-python)
48
+ ![license](https://img.shields.io/github/license/synodriver/pysilk.svg)
49
+ ![action](https://img.shields.io/github/workflow/status/synodriver/pysilk/build%20wheel)
50
+
51
+ ## 安装
52
+ ```bash
53
+ pip install silk-python
54
+ ```
55
+
56
+
57
+ ## 使用
58
+ - encode
59
+ ```python
60
+ import pysilk
61
+
62
+ with open("verybiginput.pcm", "rb") as pcm, open("output.silk", "wb") as silk:
63
+ pysilk.encode(pcm, silk, 24000, 24000)
64
+ ```
65
+
66
+ - decode
67
+
68
+ ```python
69
+ import pysilk
70
+
71
+ with open("verybiginput.silk", "rb") as silk, open("output.pcm", "wb") as pcm:
72
+ pysilk.decode(silk, pcm, 24000)
73
+ ```
74
+
75
+ ## 支持功能
76
+ - 接受任何二进制的```file-like object```,比如```BytesIO```,可以流式解码大文件
77
+ - 包装了silk的全部C接口的参数,当然他们都有合理的默认值
78
+ - 基于```Cython```, [关键部位](https://github.com/synodriver/pysilk/blob/stream/pysilk/silk.pxd#L43-L65) 内联C函数,高性能
79
+
80
+
81
+ ## 公开函数
82
+ ```python
83
+ from typing import BinaryIO
84
+
85
+ def encode(input: BinaryIO, output: BinaryIO, sample_rate: int, bit_rate: int, max_internal_sample_rate: int = 24000, packet_loss_percentage: int = 0, complexity: int = 2, use_inband_fec: bool = False, use_dtx: bool = False, tencent: bool = True) -> None: ...
86
+ def decode(input: BinaryIO, output: BinaryIO, sample_rate: int, frame_size: int = 0, frames_per_packet: int = 1, more_internal_decoder_frames: bool = False, in_band_fec_offset: int = 0, loss: bool = False) -> None: ...
87
+ ```
88
+
89
+ ## 公开异常
90
+ ```python
91
+ class SilkError(Exception):
92
+ pass
93
+ ```
94
+
95
+ ### ✨v0.2.0✨
96
+ 合并了[CFFI](https://github.com/synodriver/pysilk-cffi) 的工作
97
+
98
+ ### 本机编译
99
+ ```
100
+ python -m pip install setuptools wheel cython cffi
101
+ git clone https://github.com/synodriver/pysilk
102
+ cd pysilk
103
+ git submodule update --init --recursive
104
+ python setup.py bdist_wheel --use-cython --use-cffi
105
+ ```
106
+
107
+ ### 后端选择
108
+ 默认由py实现决定,在cpython上自动选择cython后端,在pypy上自动选择cffi后端,使用```SILK_USE_CFFI```环境变量可以强制选择cffi
@@ -0,0 +1,15 @@
1
+ pysilk/__init__.py,sha256=51ILaDOKD4UUQk0w6FjBXTjTSF8kqkOyxXNleBoUTqw,417
2
+ pysilk/backends/__init__.py,sha256=XywP1BY8lg5-vwoQw0cKnqhB-lP27C5UiVRg25FP64c,69
3
+ pysilk/backends/cffi/__init__.py,sha256=MDJqE3f01r8ahQFQH_8MFmMtHD89yhDeTmbhUuUx6Lw,8977
4
+ pysilk/backends/cffi/_silk.pyd,sha256=YHwyjEPCxW_TrePYy1Hn0kyRzEVimbLt0spiF3iVu8I,139776
5
+ pysilk/backends/cffi/build.py,sha256=dWh6JFs02S4du75NQyIGdzAmCO4uRCbh-rgKf4FdXjQ,3690
6
+ pysilk/backends/cython/__init__.py,sha256=6TA0vr_27_mdZ22s5_ZEJR0M7HcJUzPVrcMyIPRcFQ0,113
7
+ pysilk/backends/cython/_silk.c,sha256=ixNIgNj2JjwxfB9RvX-IyIiZaKdeN0MJmBzLykyevKk,571618
8
+ pysilk/backends/cython/_silk.pyd,sha256=VSo4QKHBhueuFsF7akuC9Ka63DbG5ARCGZND0utGR8Q,181248
9
+ pysilk/backends/cython/_silk.pyi,sha256=3Y39NJhDIe4ehO0HHzu9P8y0cCVC5aTUbDCgxFKks1k,690
10
+ pysilk/backends/cython/_silk.pyx,sha256=6mJ1MrKjVcKabWg-YDrNiawhKa9hzBVBC76Xt0Hn6AU,10705
11
+ pysilk/backends/cython/silk.pxd,sha256=9SKUDcJeDDIeTsScrerq1rtwSWqZLP_yaWp_N2HEOUE,2328
12
+ silk_python-0.2.7.dist-info/METADATA,sha256=pCACDqPqLMlWUiXGRTFccl8S4gbRUG_ANYmrr8m5vo4,3869
13
+ silk_python-0.2.7.dist-info/WHEEL,sha256=0ABLuJ37exXk5N_efmYNs2NU9NK1K2Qlod_6bYkofEA,97
14
+ silk_python-0.2.7.dist-info/top_level.txt,sha256=tcB-cCbL6OMj8uspHFAz4kJ8ObWLz--nuLQ1wVc0GRY,7
15
+ silk_python-0.2.7.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: false
4
+ Tag: cp313-cp313-win32
5
+
@@ -0,0 +1 @@
1
+ pysilk