videosdk-plugins-rnnoise-dev 0.0.63.dev0__tar.gz → 0.0.63.dev2__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 (16) hide show
  1. {videosdk_plugins_rnnoise_dev-0.0.63.dev0 → videosdk_plugins_rnnoise_dev-0.0.63.dev2}/PKG-INFO +3 -3
  2. {videosdk_plugins_rnnoise_dev-0.0.63.dev0 → videosdk_plugins_rnnoise_dev-0.0.63.dev2}/pyproject.toml +3 -10
  3. videosdk_plugins_rnnoise_dev-0.0.63.dev2/videosdk/plugins/rnnoise/build_rnnoise.py +71 -0
  4. {videosdk_plugins_rnnoise_dev-0.0.63.dev0 → videosdk_plugins_rnnoise_dev-0.0.63.dev2}/videosdk/plugins/rnnoise/denoise.py +20 -10
  5. videosdk_plugins_rnnoise_dev-0.0.63.dev2/videosdk/plugins/rnnoise/files/librnnoise.0.dylib +0 -0
  6. videosdk_plugins_rnnoise_dev-0.0.63.dev2/videosdk/plugins/rnnoise/files/librnnoise.dylib +1 -0
  7. videosdk_plugins_rnnoise_dev-0.0.63.dev2/videosdk/plugins/rnnoise/rnnoise.py +43 -0
  8. videosdk_plugins_rnnoise_dev-0.0.63.dev2/videosdk/plugins/rnnoise/version.py +1 -0
  9. videosdk_plugins_rnnoise_dev-0.0.63.dev0/videosdk/plugins/rnnoise/build_rnnoise.py +0 -126
  10. videosdk_plugins_rnnoise_dev-0.0.63.dev0/videosdk/plugins/rnnoise/files/librnnoise.0.dylib +0 -0
  11. videosdk_plugins_rnnoise_dev-0.0.63.dev0/videosdk/plugins/rnnoise/files/librnnoise.dylib +0 -0
  12. videosdk_plugins_rnnoise_dev-0.0.63.dev0/videosdk/plugins/rnnoise/rnnoise.py +0 -77
  13. videosdk_plugins_rnnoise_dev-0.0.63.dev0/videosdk/plugins/rnnoise/version.py +0 -1
  14. {videosdk_plugins_rnnoise_dev-0.0.63.dev0 → videosdk_plugins_rnnoise_dev-0.0.63.dev2}/README.md +0 -0
  15. {videosdk_plugins_rnnoise_dev-0.0.63.dev0 → videosdk_plugins_rnnoise_dev-0.0.63.dev2}/videosdk/plugins/rnnoise/__init__.py +0 -0
  16. {videosdk_plugins_rnnoise_dev-0.0.63.dev0 → videosdk_plugins_rnnoise_dev-0.0.63.dev2}/videosdk/plugins/rnnoise/files/librnnoise.so +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: videosdk-plugins-rnnoise-dev
3
- Version: 0.0.63.dev0
3
+ Version: 0.0.63.dev2
4
4
  Summary: VideoSDK Agent Framework plugin for RNNoise.
5
5
  Author: videosdk
6
6
  License-Expression: Apache-2.0
@@ -12,9 +12,9 @@ Classifier: Topic :: Multimedia :: Sound/Audio
12
12
  Classifier: Topic :: Multimedia :: Video
13
13
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
14
14
  Requires-Python: >=3.11
15
- Requires-Dist: numpy>=1.26
15
+ Requires-Dist: numpy>=1.27
16
16
  Requires-Dist: resampy
17
- Requires-Dist: videosdk-agents>=0.0.22
17
+ Requires-Dist: videosdk-agents>=0.0.62
18
18
  Description-Content-Type: text/markdown
19
19
 
20
20
  # VideoSDK RNNoise Plugin
@@ -9,7 +9,7 @@ description = "VideoSDK Agent Framework plugin for RNNoise."
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
11
11
  requires-python = ">=3.11"
12
- authors = [{ name = "videosdk"}]
12
+ authors = [{ name = "videosdk" }]
13
13
  keywords = ["video", "audio", "ai", "lmnt", "tts", "videosdk", "rime"]
14
14
  classifiers = [
15
15
  "Intended Audience :: Developers",
@@ -20,20 +20,13 @@ classifiers = [
20
20
  "Topic :: Multimedia :: Video",
21
21
  "Topic :: Scientific/Engineering :: Artificial Intelligence",
22
22
  ]
23
- dependencies = [
24
- "videosdk-agents>=0.0.22",
25
- "resampy",
26
- "numpy>=1.26"
27
- ]
23
+ dependencies = ["videosdk-agents>=0.0.62", "resampy", "numpy>=1.27"]
28
24
 
29
25
  [tool.hatch.version]
30
26
  path = "videosdk/plugins/rnnoise/version.py"
31
27
 
32
28
  [tool.hatch.build.targets.wheel]
33
29
  packages = ["videosdk"]
34
- include = [
35
- "videosdk/plugins/rnnoise/files/*"
36
- ]
37
30
 
38
31
  [tool.hatch.build.targets.sdist]
39
- include = ["/videosdk"]
32
+ include = ["/videosdk"]
@@ -0,0 +1,71 @@
1
+ import os
2
+ import platform
3
+ import subprocess
4
+ import shutil
5
+ import tempfile
6
+
7
+ import sys
8
+ from shutil import which
9
+
10
+ def check_command(cmd, install_tip):
11
+ if not which(cmd):
12
+ raise EnvironmentError(f"{cmd} not found. Install it: {install_tip}")
13
+
14
+ def run_subprocess(cmd, cwd=None):
15
+ print(f"Running: {' '.join(cmd)}")
16
+ try:
17
+ result = subprocess.run(cmd, cwd=cwd, check=True, capture_output=True, text=True)
18
+ print(result.stdout)
19
+ if result.stderr:
20
+ print(f"Warnings/Errors: {result.stderr}")
21
+ return result
22
+ except subprocess.CalledProcessError as e:
23
+ print(f"Command failed with code {e.returncode}: {e.stderr}")
24
+ raise
25
+
26
+ def build_rnnoise():
27
+ os_sys = platform.system()
28
+ repo_url = "https://github.com/xiph/rnnoise.git"
29
+
30
+ git_tip = "Install git (e.g., apt install git on Debian/Ubuntu, brew install git on macOS, or Chocolatey on Windows)."
31
+ check_command("git", git_tip)
32
+
33
+ with tempfile.TemporaryDirectory() as tmpdir:
34
+ run_subprocess(["git", "clone", repo_url, tmpdir])
35
+ os.chdir(tmpdir)
36
+ if os_sys == "Darwin" or os_sys == "Linux":
37
+ unix_tip = "Install build tools (e.g., apt install build-essential autoconf automake libtool on Debian/Ubuntu; brew install autoconf automake libtool on macOS)."
38
+ for tool in ["autoconf", "automake", "libtool", "make"]:
39
+ check_command(tool, unix_tip)
40
+
41
+ run_subprocess(["./autogen.sh"])
42
+ run_subprocess(["./configure"])
43
+ run_subprocess(["make"])
44
+ lib_dir = ".libs"
45
+ lib_file = "librnnoise.dylib" if os_sys == "Darwin" else "librnnoise.so"
46
+ built_lib = os.path.join(lib_dir, lib_file)
47
+ elif os_sys == "Windows":
48
+ nmake_tip = "Install Visual Studio (community edition) and run this script from Developer Command Prompt. Alternatively, use MSYS2 (install via https://www.msys2.org/) and run make in the repo."
49
+ check_command("nmake", nmake_tip)
50
+ os.chdir("msvc")
51
+ run_subprocess(["nmake", "/f", "Makefile.ms"])
52
+ built_lib = "rnnoise.dll"
53
+ else:
54
+ raise ValueError(f"Unsupported OS: {os_sys}. Manual build required (clone repo and follow README).")
55
+
56
+ if not os.path.exists(built_lib):
57
+ raise FileNotFoundError(f"Build failed: {built_lib} not found. Ensure build tools are installed and environment is set up.")
58
+
59
+ script_dir = os.path.dirname(os.path.abspath(__file__))
60
+ target_dir = os.path.join(script_dir, "files")
61
+ os.makedirs(target_dir, exist_ok=True)
62
+ shutil.copy(built_lib, os.path.join(target_dir, os.path.basename(built_lib)))
63
+
64
+ if __name__ == "__main__":
65
+ try:
66
+ build_rnnoise()
67
+ print("RNNoise library built successfully for your OS.")
68
+ except Exception as e:
69
+ print(f"Build failed: {e}")
70
+ print("If in a container/cloud/terminal, ensure tools are installed (e.g., via apt/brew/Chocolatey) or build manually per RNNoise README: https://github.com/xiph/rnnoise")
71
+ sys.exit(1)
@@ -4,12 +4,15 @@ from .rnnoise import RNN
4
4
  import numpy as np
5
5
  import resampy
6
6
 
7
+
7
8
  class RNNoise(Denoise):
8
9
  def __init__(self):
10
+ """Initialize the RNNoise denoise plugin.
11
+ """
9
12
  super().__init__()
10
13
  self.rnnoise = RNN()
11
14
  self._target_sample_rate = 48000
12
- self._frame_duration_ms = 20
15
+ self._frame_duration_ms = 20
13
16
  self._rnnoise_frame_size = 480
14
17
 
15
18
  async def denoise(self, audio_frames: bytes, **kwargs: Any) -> bytes:
@@ -18,29 +21,35 @@ class RNNoise(Denoise):
18
21
 
19
22
  audio_np = np.frombuffer(audio_frames, dtype=np.int16)
20
23
  num_samples = len(audio_np)
21
- original_sample_rate = int(num_samples * 1000 / self._frame_duration_ms)
24
+ original_sample_rate = int(
25
+ num_samples * 1000 / self._frame_duration_ms)
22
26
 
23
27
  if original_sample_rate != self._target_sample_rate:
24
28
  audio_float = audio_np.astype(np.float32) / 32767.0
25
- resampled_audio_float = resampy.resample(audio_float, sr_orig=original_sample_rate, sr_new=self._target_sample_rate)
26
- resampled_audio_np = (resampled_audio_float * 32767.0).astype(np.int16)
29
+ resampled_audio_float = resampy.resample(
30
+ audio_float, sr_orig=original_sample_rate, sr_new=self._target_sample_rate)
31
+ resampled_audio_np = (resampled_audio_float *
32
+ 32767.0).astype(np.int16)
27
33
  else:
28
34
  resampled_audio_np = audio_np
29
35
 
30
- num_rnnoise_frames = len(resampled_audio_np) // self._rnnoise_frame_size
36
+ num_rnnoise_frames = len(
37
+ resampled_audio_np) // self._rnnoise_frame_size
31
38
  denoised_chunks = []
32
39
 
33
40
  for i in range(num_rnnoise_frames):
34
41
  start = i * self._rnnoise_frame_size
35
42
  end = start + self._rnnoise_frame_size
36
43
  chunk = resampled_audio_np[start:end]
37
-
44
+
38
45
  if len(chunk) != self._rnnoise_frame_size:
39
46
  continue
40
47
 
41
48
  chunk_bytes = chunk.tobytes()
42
- _vod_prob, denoised_chunk_bytes = self.rnnoise.process_frame(chunk_bytes)
43
- denoised_chunk_np = np.frombuffer(denoised_chunk_bytes, dtype=np.int16)
49
+ _vod_prob, denoised_chunk_bytes = self.rnnoise.process_frame(
50
+ chunk_bytes)
51
+ denoised_chunk_np = np.frombuffer(
52
+ denoised_chunk_bytes, dtype=np.int16)
44
53
  denoised_chunks.append(denoised_chunk_np)
45
54
 
46
55
  if not denoised_chunks:
@@ -50,7 +59,8 @@ class RNNoise(Denoise):
50
59
 
51
60
  if original_sample_rate != self._target_sample_rate:
52
61
  denoised_float = denoised_audio_np.astype(np.float32) / 32767.0
53
- original_format_float = resampy.resample(denoised_float, sr_orig=self._target_sample_rate, sr_new=original_sample_rate)
62
+ original_format_float = resampy.resample(
63
+ denoised_float, sr_orig=self._target_sample_rate, sr_new=original_sample_rate)
54
64
  final_audio_np = (original_format_float * 32767.0).astype(np.int16)
55
65
  else:
56
66
  final_audio_np = denoised_audio_np
@@ -59,4 +69,4 @@ class RNNoise(Denoise):
59
69
 
60
70
  async def aclose(self) -> None:
61
71
  self.rnnoise.destroy()
62
- await super().aclose()
72
+ await super().aclose()
@@ -0,0 +1,43 @@
1
+ import ctypes,numpy,os
2
+ import platform
3
+
4
+ script_dir = os.path.dirname(os.path.abspath(__file__))
5
+
6
+
7
+ sys_name = platform.system()
8
+ if sys_name == "Darwin":
9
+ lib_name = "librnnoise.dylib"
10
+ elif sys_name == "Linux":
11
+ lib_name = "librnnoise.so"
12
+ elif sys_name == "Windows":
13
+ lib_name = "rnnoise.dll"
14
+ else:
15
+ raise OSError(f"Unsupported OS: {sys_name}")
16
+
17
+ lib_path = os.path.join(script_dir, "files", lib_name)
18
+
19
+ try:
20
+ lib = ctypes.cdll.LoadLibrary(lib_path)
21
+ except OSError as e:
22
+ raise OSError(
23
+ f"Error loading rnnoise library at {lib_path}. "
24
+ f"It may be corrupted or incompatible with your platform. "
25
+ f"Original error: {e}"
26
+ ) from e
27
+
28
+ lib.rnnoise_process_frame.argtypes = [ctypes.c_void_p,ctypes.POINTER(ctypes.c_float),ctypes.POINTER(ctypes.c_float)]
29
+ lib.rnnoise_process_frame.restype = ctypes.c_float
30
+ lib.rnnoise_create.restype = ctypes.c_void_p
31
+ lib.rnnoise_destroy.argtypes = [ctypes.c_void_p]
32
+
33
+ class RNN(object):
34
+ def __init__(self):
35
+ self.obj = lib.rnnoise_create()
36
+ def process_frame(self,inbuf):
37
+ outbuf = numpy.ndarray((480,), 'h', inbuf).astype(ctypes.c_float)
38
+ outbuf_ptr = outbuf.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
39
+ VodProb = lib.rnnoise_process_frame(self.obj,outbuf_ptr,outbuf_ptr)
40
+ return (VodProb,outbuf.astype(ctypes.c_short).tobytes())
41
+
42
+ def destroy(self):
43
+ lib.rnnoise_destroy(self.obj)
@@ -0,0 +1 @@
1
+ __version__ = "0.0.63.dev2"
@@ -1,126 +0,0 @@
1
- import os
2
- import platform
3
- import subprocess
4
- import shutil
5
- import tempfile
6
-
7
- import sys
8
- from shutil import which
9
-
10
- def check_command(cmd, install_tip):
11
- if not which(cmd):
12
- raise EnvironmentError(f"{cmd} not found. Install it: {install_tip}")
13
-
14
- def run_subprocess(cmd, cwd=None):
15
- print(f"Running: {' '.join(cmd)}")
16
- try:
17
- result = subprocess.run(cmd, cwd=cwd, check=True, capture_output=True, text=True)
18
- print(result.stdout)
19
- if result.stderr:
20
- print(f"Warnings/Errors: {result.stderr}")
21
- return result
22
- except subprocess.CalledProcessError as e:
23
- print(f"Command failed with code {e.returncode}: {e.stderr}")
24
- raise
25
-
26
- def build_rnnoise():
27
- # Force Linux detection when running in Docker
28
- if os.path.exists("/.dockerenv") or os.environ.get("DOCKER_CONTAINER"):
29
- os_sys = "Linux"
30
- else:
31
- os_sys = platform.system()
32
- repo_url = "https://github.com/xiph/rnnoise.git"
33
-
34
- git_tip = "Install git (e.g., apt install git on Debian/Ubuntu, brew install git on macOS, or Chocolatey on Windows)."
35
- check_command("git", git_tip)
36
-
37
- with tempfile.TemporaryDirectory() as tmpdir:
38
- run_subprocess(["git", "clone", repo_url, tmpdir])
39
- os.chdir(tmpdir)
40
- if os_sys == "Darwin" or os_sys == "Linux":
41
- # Check required Unix build tools
42
- unix_tip = "Install build tools (e.g., apt install build-essential autoconf automake libtool on Debian/Ubuntu; brew install autoconf automake libtool on macOS)."
43
- for tool in ["autoconf", "automake", "libtool", "make"]:
44
- check_command(tool, unix_tip)
45
-
46
- # Generate build files and compile
47
- run_subprocess(["./autogen.sh"])
48
- run_subprocess(["./configure"])
49
- run_subprocess(["make"])
50
- lib_dir = ".libs"
51
-
52
- # Force Linux .so file when running in Docker container
53
- if os.path.exists("/.dockerenv") or os.environ.get("DOCKER_CONTAINER"):
54
- lib_file = "librnnoise.so"
55
- print(f"🔧 Docker detected, forcing .so file: {lib_file}")
56
- else:
57
- lib_file = "librnnoise.dylib" if os_sys == "Darwin" else "librnnoise.so"
58
- print(f"🔧 Host system detected: {os_sys}, using: {lib_file}")
59
-
60
- built_lib = os.path.join(lib_dir, lib_file)
61
- elif os_sys == "Windows":
62
- # Check nmake for Visual Studio-based build
63
- nmake_tip = "Install Visual Studio (community edition) and run this script from Developer Command Prompt. Alternatively, use MSYS2 (install via https://www.msys2.org/) and run make in the repo."
64
- check_command("nmake", nmake_tip)
65
-
66
- os.chdir("msvc")
67
- # Assumes Visual Studio is installed; run from Developer Command Prompt if needed
68
- run_subprocess(["nmake", "/f", "Makefile.ms"])
69
- built_lib = "rnnoise.dll" # Adjust if name differs after build
70
- else:
71
- raise ValueError(f"Unsupported OS: {os_sys}. Manual build required (clone repo and follow README).")
72
-
73
- if not os.path.exists(built_lib):
74
- raise FileNotFoundError(f"Build failed: {built_lib} not found. Ensure build tools are installed and environment is set up (e.g., in containers, add tools via Dockerfile/package manager).")
75
-
76
- script_dir = os.path.dirname(os.path.abspath(__file__))
77
- target_dir = os.path.join(script_dir, "files")
78
- os.makedirs(target_dir, exist_ok=True)
79
-
80
- # Force .so files when running in Docker
81
- if os.path.exists("/.dockerenv") or os.environ.get("DOCKER_CONTAINER"):
82
- # Look for shared library specifically
83
- shared_lib = os.path.join(lib_dir, "librnnoise.so")
84
- static_lib = os.path.join(lib_dir, "librnnoise.a")
85
-
86
- if os.path.exists(shared_lib):
87
- source_lib = shared_lib
88
- print(f"🔧 Found shared library: {source_lib}")
89
- elif os.path.exists(static_lib):
90
- # If no shared library, create one from static library
91
- print(f"🔧 Creating shared library from static library")
92
- # Extract object files from static library
93
- run_subprocess(["ar", "-x", static_lib])
94
- # Create shared library from object files
95
- obj_files = [f for f in os.listdir(".") if f.endswith(".o")]
96
- run_subprocess(["gcc", "-shared", "-o", shared_lib] + obj_files + ["-lm"])
97
- source_lib = shared_lib
98
- else:
99
- raise FileNotFoundError(f"No librnnoise library found in {lib_dir}")
100
-
101
- target_lib = os.path.join(target_dir, "librnnoise.so")
102
- shutil.copy(source_lib, target_lib)
103
- print(f"🔧 Copied {source_lib} to {target_lib}")
104
-
105
- # Also create a symlink for compatibility
106
- symlink_path = os.path.join(target_dir, "librnnoise.dylib")
107
- if os.path.exists(symlink_path):
108
- os.remove(symlink_path)
109
- os.symlink("librnnoise.so", symlink_path)
110
- print(f"🔧 Created symlink: librnnoise.dylib -> librnnoise.so")
111
-
112
- # Copy to the mounted volume location
113
- mounted_target = "/output/librnnoise.so"
114
- shutil.copy(source_lib, mounted_target)
115
- print(f"🔧 Copied to mounted volume: {mounted_target}")
116
- else:
117
- shutil.copy(built_lib, os.path.join(target_dir, os.path.basename(built_lib)))
118
-
119
- if __name__ == "__main__":
120
- try:
121
- build_rnnoise()
122
- print("RNNoise library built successfully for your OS.")
123
- except Exception as e:
124
- print(f"Build failed: {e}")
125
- print("If in a container/cloud/terminal, ensure tools are installed (e.g., via apt/brew/Chocolatey) or build manually per RNNoise README: https://github.com/xiph/rnnoise")
126
- sys.exit(1)
@@ -1,77 +0,0 @@
1
- import ctypes
2
- import numpy as np
3
- import os
4
- import platform
5
-
6
- script_dir = os.path.dirname(os.path.abspath(__file__))
7
-
8
-
9
- sys_name = platform.system()
10
- if sys_name == "Darwin":
11
- lib_name = "librnnoise.dylib"
12
- elif sys_name == "Linux":
13
- lib_name = "librnnoise.so"
14
- elif sys_name == "Windows":
15
- lib_name = "rnnoise.dll"
16
- else:
17
- raise OSError(f"Unsupported OS: {sys_name}")
18
-
19
- lib_path = os.path.join(script_dir, "files", lib_name)
20
-
21
- try:
22
- lib = ctypes.cdll.LoadLibrary(lib_path)
23
- except OSError as e:
24
- raise OSError(
25
- f"Error loading rnnoise library at {lib_path}. "
26
- f"It may be corrupted or incompatible with your platform. "
27
- f"Original error: {e}"
28
- ) from e
29
-
30
- # Define the correct function signatures
31
- lib.rnnoise_create.argtypes = [ctypes.c_void_p] # RNNModel *model (can be NULL)
32
- lib.rnnoise_create.restype = ctypes.c_void_p
33
- lib.rnnoise_destroy.argtypes = [ctypes.c_void_p]
34
- lib.rnnoise_process_frame.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float)]
35
- lib.rnnoise_process_frame.restype = ctypes.c_float
36
-
37
- class RNN(object):
38
- def __init__(self):
39
- # Pass NULL (None) for the model parameter to use the default model
40
- self.obj = lib.rnnoise_create(None)
41
- if self.obj is None:
42
- raise RuntimeError("Failed to create RNNoise instance")
43
-
44
- def process_frame(self, inbuf):
45
- # Create a copy of the input buffer to avoid modifying the original
46
- if isinstance(inbuf, bytes):
47
- # Convert bytes to numpy array
48
- audio_data = np.frombuffer(inbuf, dtype=np.int16)
49
- else:
50
- audio_data = np.array(inbuf, dtype=np.int16)
51
-
52
- # Ensure we have exactly 480 samples
53
- if len(audio_data) != 480:
54
- raise ValueError(f"Expected 480 samples, got {len(audio_data)}")
55
-
56
- # Convert to float32 and normalize
57
- audio_float = audio_data.astype(np.float32) / 32767.0
58
-
59
- # Create output buffer
60
- outbuf = np.zeros(480, dtype=np.float32)
61
-
62
- # Get pointers
63
- in_ptr = audio_float.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
64
- out_ptr = outbuf.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
65
-
66
- # Process the frame
67
- VodProb = lib.rnnoise_process_frame(self.obj, out_ptr, in_ptr)
68
-
69
- # Convert back to int16
70
- outbuf_int16 = (outbuf * 32767.0).astype(np.int16)
71
-
72
- return (VodProb, outbuf_int16.tobytes())
73
-
74
- def destroy(self):
75
- if self.obj is not None:
76
- lib.rnnoise_destroy(self.obj)
77
- self.obj = None
@@ -1 +0,0 @@
1
- __version__ = "0.0.63.dev0"