audio.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. # -*- coding: utf-8 -*-
  2. """
  3. Audio Extension Points.
  4. Extension Points für Audio-Verarbeitung und -Effekte.
  5. """
  6. from abc import abstractmethod
  7. from typing import Any, TYPE_CHECKING
  8. from trixy_core.plugins.extensions.extension import Extension
  9. from trixy_core.plugins.extensions.extension_point import ExtensionPoint, get_global_registry
  10. if TYPE_CHECKING:
  11. from trixy_core.audio.processing.processor import AudioProcessor
  12. # Extension Point IDs
  13. AUDIO_PROCESSOR_POINT = "audio.processor"
  14. class AudioProcessorExtension(Extension["AudioProcessor"]):
  15. """
  16. Extension für Audio-Prozessoren.
  17. Ermöglicht Plugins, Audio-Streams zu verarbeiten:
  18. - Ducking (Lautstärke bei Wakeword/Conversation reduzieren)
  19. - Crossfade (Übergänge zwischen Tracks)
  20. - Equalizer (Frequenz-Anpassungen)
  21. - Effekte (Hall, Echo, etc.)
  22. - Limiter/Compressor
  23. - Analyse (Visualisierung, BPM-Erkennung)
  24. Beispiel:
  25. class DuckingExtension(AudioProcessorExtension):
  26. def __init__(self, plugin_name: str):
  27. super().__init__(
  28. "ducking_processor",
  29. "Ducking",
  30. plugin_name,
  31. priority=300,
  32. description="Reduziert Musik bei Sprachausgabe",
  33. )
  34. async def create_instance(self, config):
  35. from my_plugin.processors import DuckingProcessor
  36. return DuckingProcessor(
  37. duck_factor=config.get("duck_factor", 0.3),
  38. fade_duration_ms=config.get("fade_duration_ms", 500),
  39. )
  40. """
  41. def __init__(
  42. self,
  43. extension_id: str,
  44. name: str,
  45. plugin_name: str = "",
  46. priority: int = 500,
  47. description: str = "",
  48. category: str = "effect",
  49. ) -> None:
  50. """
  51. Initialisiert die AudioProcessor Extension.
  52. Args:
  53. extension_id: Eindeutige ID
  54. name: Anzeigename
  55. plugin_name: Plugin-Name
  56. priority: Priorität in der Pipeline (niedriger = früher)
  57. description: Beschreibung
  58. category: Kategorie (effect, analysis, utility)
  59. """
  60. super().__init__(extension_id, name, plugin_name)
  61. self._info.description = description
  62. self._info.extension_point = AUDIO_PROCESSOR_POINT
  63. self._info.metadata["priority"] = priority
  64. self._info.metadata["category"] = category
  65. @property
  66. def priority(self) -> int:
  67. """Priorität in der Processing-Pipeline."""
  68. return self._info.metadata.get("priority", 500)
  69. @property
  70. def category(self) -> str:
  71. """Kategorie des Prozessors."""
  72. return self._info.metadata.get("category", "effect")
  73. @abstractmethod
  74. async def create_instance(self, config: dict[str, Any]) -> "AudioProcessor":
  75. """
  76. Erstellt die AudioProcessor-Instanz.
  77. Args:
  78. config: Konfiguration für den Prozessor
  79. Returns:
  80. Konfigurierte AudioProcessor-Instanz
  81. """
  82. pass
  83. def setup_audio_extension_points() -> dict[str, ExtensionPoint]:
  84. """
  85. Richtet alle Audio Extension Points ein.
  86. Returns:
  87. Dict mit allen erstellten Extension Points
  88. """
  89. registry = get_global_registry()
  90. points = {}
  91. # Audio-Prozessoren
  92. points[AUDIO_PROCESSOR_POINT] = registry.create_point(
  93. id=AUDIO_PROCESSOR_POINT,
  94. name="Audio-Prozessoren",
  95. description=(
  96. "Erweiterung um Audio-Verarbeitung: "
  97. "Ducking, Crossfade, Equalizer, Effekte, etc."
  98. ),
  99. category="audio",
  100. allows_multiple=True,
  101. )
  102. return points
  103. def get_audio_processors() -> list["AudioProcessor"]:
  104. """
  105. Holt alle registrierten Audio-Prozessoren.
  106. Returns:
  107. Liste aller AudioProcessor-Instanzen
  108. """
  109. registry = get_global_registry()
  110. point = registry.get_point(AUDIO_PROCESSOR_POINT)
  111. if point:
  112. return point.get_all_instances()
  113. return []
  114. def get_audio_processor_extensions() -> list[AudioProcessorExtension]:
  115. """
  116. Holt alle registrierten AudioProcessor-Extensions.
  117. Returns:
  118. Liste aller Extensions
  119. """
  120. registry = get_global_registry()
  121. point = registry.get_point(AUDIO_PROCESSOR_POINT)
  122. if point:
  123. return [e for e in point.extensions if isinstance(e, AudioProcessorExtension)]
  124. return []