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.
pysilk/__init__.py ADDED
@@ -0,0 +1,22 @@
1
+ import os
2
+ import platform
3
+
4
+ impl = platform.python_implementation()
5
+
6
+
7
+ def _should_use_cffi() -> bool:
8
+ ev = os.getenv("SILK_USE_CFFI")
9
+ if ev is not None:
10
+ return True
11
+ if impl == "CPython":
12
+ return False
13
+ else:
14
+ return True
15
+
16
+
17
+ if not _should_use_cffi():
18
+ from pysilk.backends.cython import *
19
+ else:
20
+ from pysilk.backends.cffi import *
21
+
22
+ __version__ = "0.2.7"
@@ -0,0 +1,3 @@
1
+ """
2
+ Copyright (c) 2008-2021 synodriver <synodriver@gmail.com>
3
+ """
@@ -0,0 +1,264 @@
1
+ import struct
2
+ from typing import IO
3
+
4
+ from pysilk.backends.cffi._silk import ffi, lib
5
+
6
+
7
+
8
+ class SilkError(Exception):
9
+ def __init__(self, code):
10
+ self.code = code
11
+
12
+ def __str__(self):
13
+ if isinstance(self.code, int):
14
+ if self.code == -1:
15
+ return "ENC_INPUT_INVALID_NO_OF_SAMPLES"
16
+ elif self.code == -2:
17
+ return "ENC_FS_NOT_SUPPORTED"
18
+ elif self.code == -3:
19
+ return "ENC_PACKET_SIZE_NOT_SUPPORTED"
20
+ elif self.code == -4:
21
+ return "ENC_PAYLOAD_BUF_TOO_SHORT"
22
+ elif self.code == -5:
23
+ return "ENC_INVALID_LOSS_RATE"
24
+ elif self.code == -6:
25
+ return "ENC_INVALID_COMPLEXITY_SETTING"
26
+ elif self.code == -7:
27
+ return "ENC_INVALID_INBAND_FEC_SETTING"
28
+ elif self.code == -8:
29
+ return "ENC_INVALID_DTX_SETTING"
30
+ elif self.code == -9:
31
+ return "ENC_INTERNAL_ERROR"
32
+ elif self.code == -10:
33
+ return "DEC_INVALID_SAMPLING_FREQUENCY"
34
+ elif self.code == -11:
35
+ return "DEC_PAYLOAD_TOO_LARGE"
36
+ elif self.code == -12:
37
+ return "DEC_PAYLOAD_ERROR"
38
+ else:
39
+ return "Other error"
40
+ else:
41
+ return str(self.code)
42
+
43
+
44
+ def i16_to_bytes(data: int) -> bytes:
45
+ return struct.pack("=h", data)
46
+
47
+
48
+ def bytes_to_i16(data: bytes) -> int:
49
+ return struct.unpack("=h", data)[0]
50
+
51
+
52
+ def write_i16_le(output: IO, data: int):
53
+ if lib.SHOULD_SWAP():
54
+ data = lib.swap_i16(data)
55
+ output.write(i16_to_bytes(data))
56
+
57
+
58
+ def read_i16_le(input: IO) -> int:
59
+ chunk = input.read(2) # type: bytes
60
+ data: int = bytes_to_i16(chunk)
61
+ if lib.SHOULD_SWAP():
62
+ data = lib.swap_i16(data)
63
+ return data
64
+
65
+
66
+ def check_file(file) -> bool:
67
+ if hasattr(file, "read") and hasattr(file, "write"):
68
+ return True
69
+ return False
70
+
71
+
72
+ def encode(
73
+ input: IO,
74
+ output: IO,
75
+ sample_rate: int,
76
+ bit_rate: int,
77
+ max_internal_sample_rate: int = 24000,
78
+ packet_loss_percentage: int = 0,
79
+ complexity: int = 2,
80
+ use_inband_fec: bool = False,
81
+ use_dtx: bool = False,
82
+ tencent: bool = True,
83
+ ) -> None:
84
+ """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
85
+ encode pcm to silk
86
+ :param input: BytesIO or an openfile with "rb" mode
87
+ :param output: BytesIO or an openfile with "wb" mode
88
+ :param sample_rate:
89
+ :param bit_rate:
90
+ :param max_internal_sample_rate:
91
+ :param packet_loss_percentage:
92
+ :param complexity:
93
+ :param use_inband_fec:
94
+ :param use_dtx:
95
+ :param tencent: Tencent's special tag
96
+ :return: None
97
+ """
98
+ if not check_file(input):
99
+ raise TypeError(
100
+ "input except a file-like object, got %s" % type(input).__name__
101
+ )
102
+ if not check_file(output):
103
+ raise TypeError(
104
+ "output except a file-like object, got %s" % type(output).__name__
105
+ )
106
+
107
+ enc_control = ffi.new("SKP_SILK_SDK_EncControlStruct *")
108
+ enc_control.API_sampleRate = sample_rate
109
+ enc_control.maxInternalSampleRate = max_internal_sample_rate
110
+ enc_control.packetSize = (20 * sample_rate) // 1000
111
+ enc_control.bitRate = bit_rate
112
+ enc_control.packetLossPercentage = packet_loss_percentage
113
+ enc_control.complexity = complexity
114
+ enc_control.useInBandFEC = use_inband_fec
115
+ enc_control.useDTX = use_dtx
116
+
117
+ enc_status = ffi.new("SKP_SILK_SDK_EncControlStruct *")
118
+ enc_status.API_sampleRate = 0
119
+ enc_status.maxInternalSampleRate = 0
120
+ enc_status.packetSize = 0
121
+ enc_status.bitRate = 0
122
+ enc_status.packetLossPercentage = 0
123
+ enc_status.complexity = 0
124
+ enc_status.useInBandFEC = 0
125
+ enc_status.useDTX = 0
126
+
127
+ enc_size_bytes = ffi.new("int32_t *", 0)
128
+ code: int = lib.SKP_Silk_SDK_Get_Encoder_Size(enc_size_bytes)
129
+ if code != 0:
130
+ raise SilkError(code)
131
+ enc = lib.PyMem_Malloc(enc_size_bytes[0])
132
+ if enc == ffi.NULL:
133
+ raise MemoryError
134
+ code = lib.SKP_Silk_SDK_InitEncoder(enc, enc_status)
135
+ if code != 0:
136
+ lib.PyMem_Free(enc)
137
+ raise SilkError(code)
138
+ frame_size: int = sample_rate // 1000 * 40
139
+ if tencent:
140
+ output.write(b"\x02#!SILK_V3")
141
+ else:
142
+ output.write(b"#!SILK_V3")
143
+ n_bytes = ffi.new("int16_t *", 1250)
144
+ payload = ffi.new("uint8_t[1250]")
145
+ try:
146
+ while True:
147
+ chunk = input.read(frame_size) # type: bytes
148
+ if not isinstance(chunk, bytes):
149
+ raise TypeError(
150
+ f"input must be a file-like rb object, got {type(input).__name__}"
151
+ )
152
+
153
+ n_bytes[0] = 1250
154
+ if len(chunk) < frame_size:
155
+ break
156
+ c_chunk = ffi.from_buffer("int16_t[]", chunk)
157
+ code = lib.SKP_Silk_SDK_Encode(
158
+ enc, enc_control, c_chunk, len(chunk) // 2, payload, n_bytes
159
+ )
160
+ if code != 0:
161
+ raise SilkError(code)
162
+
163
+ write_i16_le(output, n_bytes[0])
164
+ output.write(ffi.unpack(ffi.cast("char *", payload), n_bytes[0]))
165
+ finally:
166
+ lib.PyMem_Free(enc)
167
+
168
+
169
+ def decode(
170
+ input: IO,
171
+ output: IO,
172
+ sample_rate: int,
173
+ frame_size: int = 0,
174
+ frames_per_packet: int = 1,
175
+ more_internal_decoder_frames: bool = False,
176
+ in_band_fec_offset: int = 0,
177
+ loss: bool = False,
178
+ ) -> None:
179
+ """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
180
+ decode silk to pcm
181
+ :param input:
182
+ :param output:
183
+ :param sample_rate:
184
+ :param frame_size:
185
+ :param frames_per_packet:
186
+ :param more_internal_decoder_frames:
187
+ :param in_band_fec_offset:
188
+ :param loss:
189
+ :return:
190
+ """
191
+ if not check_file(input):
192
+ raise TypeError(
193
+ "input except a file-like object, got %s" % type(input).__name__
194
+ )
195
+ if not check_file(output):
196
+ raise TypeError(
197
+ "output except a file-like object, got %s" % type(output).__name__
198
+ )
199
+
200
+ chunk = input.read(9) # type: bytes
201
+ if not isinstance(chunk, bytes):
202
+ raise TypeError(
203
+ f"input must be a file-like rb object, got {type(input).__name__}"
204
+ )
205
+ if chunk != b"#!SILK_V3" and chunk != b"\x02#!SILK_V":
206
+ raise SilkError("INVALID")
207
+ elif chunk == b"\x02#!SILK_V":
208
+ chunk = input.read(1)
209
+ if chunk != b"3":
210
+ raise SilkError("INVALID")
211
+
212
+ dec_control = ffi.new("SKP_SILK_SDK_DecControlStruct *")
213
+ dec_control.API_sampleRate = sample_rate
214
+ dec_control.frameSize = frame_size
215
+ dec_control.framesPerPacket = frames_per_packet
216
+ dec_control.moreInternalDecoderFrames = more_internal_decoder_frames
217
+ dec_control.inBandFECOffset = in_band_fec_offset
218
+ dec_size = ffi.new("int32_t *", 0)
219
+ code: int = lib.SKP_Silk_SDK_Get_Decoder_Size(dec_size)
220
+ if code != 0:
221
+ raise SilkError(code)
222
+ dec = lib.PyMem_Malloc(dec_size[0])
223
+ if dec == ffi.NULL:
224
+ raise MemoryError
225
+ code = lib.SKP_Silk_SDK_InitDecoder(dec)
226
+ if code != 0:
227
+ lib.PyMem_Free(dec)
228
+ raise SilkError(code)
229
+ frame_size = sample_rate // 1000 * 40
230
+ # cdef uint8_t buf[frame_size] # otherwise need malloc
231
+ buf = lib.PyMem_Malloc(frame_size)
232
+ if buf == ffi.NULL:
233
+ lib.PyMem_Free(dec)
234
+ raise MemoryError
235
+ n_bytes = ffi.new("int16_t *")
236
+ try:
237
+ while True:
238
+ chunk = input.read(2)
239
+ if len(chunk) < 2:
240
+ break
241
+ n_bytes[0] = bytes_to_i16(chunk)
242
+ if lib.SHOULD_SWAP():
243
+ n_bytes[0] = lib.swap_i16(n_bytes[0])
244
+ if n_bytes[0] > frame_size:
245
+ raise SilkError("INVALID")
246
+ chunk = input.read(n_bytes[0]) # type: bytes
247
+ if len(chunk) < n_bytes[0]: # not enough data
248
+ raise SilkError("INVALID")
249
+ c_chunk = ffi.from_buffer("uint8_t[]", chunk)
250
+ code = lib.SKP_Silk_SDK_Decode(
251
+ dec,
252
+ dec_control,
253
+ loss,
254
+ c_chunk,
255
+ n_bytes[0],
256
+ ffi.cast("int16_t *", buf),
257
+ n_bytes,
258
+ )
259
+ if code != 0:
260
+ raise SilkError(code)
261
+ output.write(ffi.unpack(ffi.cast("char*", buf), n_bytes[0] * 2))
262
+ finally:
263
+ lib.PyMem_Free(buf)
264
+ lib.PyMem_Free(dec)
Binary file
@@ -0,0 +1,97 @@
1
+ import glob
2
+ import sys
3
+
4
+ from cffi import FFI
5
+
6
+ ffibuilder = FFI()
7
+ ffibuilder.cdef(
8
+ """
9
+ typedef struct {
10
+ /* I: Input signal sampling rate in Hertz; 8000/12000/16000/24000 */
11
+ int API_sampleRate;
12
+ /* I: Maximum internal sampling rate in Hertz; 8000/12000/16000/24000 */
13
+ int maxInternalSampleRate;
14
+ /* I: Number of samples per packet; must be equivalent of 20, 40, 60, 80 or 100 ms */
15
+ int packetSize;
16
+ /* I: Bitrate during active speech in bits/second; internally limited */
17
+ int bitRate;
18
+ /* I: Uplink packet loss in percent (0-100) */
19
+ int packetLossPercentage;
20
+
21
+ /* I: Complexity mode; 0 is lowest; 1 is medium and 2 is highest complexity */
22
+ int complexity;
23
+ /* I: Flag to enable in-band Forward Error Correction (FEC); 0/1 */
24
+ int useInBandFEC;
25
+ /* I: Flag to enable discontinuous transmission (DTX); 0/1 */
26
+ int useDTX;
27
+ } SKP_SILK_SDK_EncControlStruct;
28
+ typedef struct {
29
+ /* I: Output signal sampling rate in Hertz; 8000/12000/16000/24000 */
30
+ int API_sampleRate;
31
+ /* O: Number of samples per frame */
32
+ int frameSize;
33
+ /* O: Frames per packet 1, 2, 3, 4, 5 */
34
+ int framesPerPacket;
35
+ /* O: Flag to indicate that the decoder has remaining payloads internally */
36
+ int moreInternalDecoderFrames;
37
+ /* O: Distance between main payload and redundant payload in packets */
38
+ int inBandFECOffset;
39
+ } SKP_SILK_SDK_DecControlStruct;
40
+ int32_t SKP_Silk_SDK_Get_Encoder_Size(int32_t *encSizeBytes);
41
+ int32_t SKP_Silk_SDK_InitEncoder(void *encState, SKP_SILK_SDK_EncControlStruct *encStatus);
42
+ int32_t SKP_Silk_SDK_Encode(void *encState,
43
+ const SKP_SILK_SDK_EncControlStruct *encControl,
44
+ const int16_t *samplesIn,
45
+ int32_t nSamplesIn,
46
+ uint8_t *outData,
47
+ int16_t *nBytesOut);
48
+ int32_t SKP_Silk_SDK_Get_Decoder_Size(int32_t *decSizeBytes);
49
+ int32_t SKP_Silk_SDK_InitDecoder(void *decState);
50
+ int32_t SKP_Silk_SDK_Decode(void * decState,
51
+ SKP_SILK_SDK_DecControlStruct *decControl,
52
+ int32_t lostFlag,
53
+ const uint8_t *inData,
54
+ const int32_t nBytesIn,
55
+ int16_t *samplesOut,
56
+ int16_t *nSamplesOut);
57
+ uint8_t is_le();
58
+ int16_t swap_i16(int16_t data);
59
+ int SHOULD_SWAP();
60
+ void *PyMem_Malloc(size_t n);
61
+ void PyMem_Free(void* p);
62
+ """
63
+ )
64
+
65
+ source = """
66
+ #include "SKP_Silk_typedef.h"
67
+ #include "SKP_Silk_SDK_API.h"
68
+ #include "SKP_Silk_control.h"
69
+ uint8_t is_le()
70
+ {
71
+ uint16_t data=1;
72
+ return *(uint8_t*)&data;
73
+ }
74
+ #ifdef _WIN32
75
+ #define swap_i16 _byteswap_ushort
76
+ #else
77
+ #define swap_i16 __builtin_bswap16
78
+ #endif /* _WIN32 */
79
+ #ifdef WORDS_BIGENDIAN
80
+ #define SHOULD_SWAP() 1
81
+ #else
82
+ #define SHOULD_SWAP() 0
83
+ #endif
84
+ """
85
+ macro_base = []
86
+ if sys.byteorder != "little":
87
+ macro_base.append(("WORDS_BIGENDIAN", None))
88
+ ffibuilder.set_source(
89
+ "pysilk.backends.cffi._silk",
90
+ source,
91
+ sources=glob.glob("./silk-v3-decoder/silk/src/*.c"),
92
+ include_dirs=["./silk-v3-decoder/silk/interface"],
93
+ define_macros=macro_base,
94
+ )
95
+
96
+ if __name__ == "__main__":
97
+ ffibuilder.compile()
@@ -0,0 +1,4 @@
1
+ """
2
+ Copyright (c) 2008-2021 synodriver <synodriver@gmail.com>
3
+ """
4
+ from pysilk.backends.cython._silk import *