ciaochris commited on
Commit
f402b3e
·
verified ·
1 Parent(s): 06be99a

Create rhythma.py

Browse files
Files changed (1) hide show
  1. rhythma.py +201 -0
rhythma.py ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import matplotlib.pyplot as plt
3
+ from scipy import signal
4
+ import pandas as pd
5
+
6
+ class RhythmaModulationEngine:
7
+ """
8
+ Rhythma: The Living Modulation Engine
9
+ A dynamic rhythm-based audio modulation system that creates responsive
10
+ sound experiences based on rhythm patterns.
11
+ """
12
+
13
+ def __init__(self, base_freq, modulation_type, rhythm_pattern):
14
+ """
15
+ Initialize the RhythmaModulationEngine.
16
+
17
+ Args:
18
+ base_freq (float): The base frequency in Hz
19
+ modulation_type (str): Type of modulation (sine, pulse, chirp)
20
+ rhythm_pattern (str): Pattern type (calm, active, focused, relaxed)
21
+ """
22
+ self.base_freq = base_freq
23
+ self.modulation_type = modulation_type
24
+ self.rhythm_pattern = rhythm_pattern
25
+ self.sample_rate = 44100 # Standard audio sample rate
26
+
27
+ # Configure rhythm patterns
28
+ self.rhythm_configs = {
29
+ "calm": {
30
+ "mod_depth": 0.15,
31
+ "mod_freq": 0.5,
32
+ "pulse_width": 0.7,
33
+ "phase_shift": 0.1,
34
+ "harmonics": [1.0, 0.5, 0.25, 0.125]
35
+ },
36
+ "active": {
37
+ "mod_depth": 0.4,
38
+ "mod_freq": 2.5,
39
+ "pulse_width": 0.3,
40
+ "phase_shift": 0.3,
41
+ "harmonics": [1.0, 0.7, 0.5, 0.3]
42
+ },
43
+ "focused": {
44
+ "mod_depth": 0.25,
45
+ "mod_freq": 1.5,
46
+ "pulse_width": 0.5,
47
+ "phase_shift": 0.2,
48
+ "harmonics": [1.0, 0.6, 0.3, 0.15]
49
+ },
50
+ "relaxed": {
51
+ "mod_depth": 0.2,
52
+ "mod_freq": 0.3,
53
+ "pulse_width": 0.8,
54
+ "phase_shift": 0.05,
55
+ "harmonics": [1.0, 0.4, 0.2, 0.1]
56
+ }
57
+ }
58
+
59
+ # Get current rhythm config
60
+ self.config = self.rhythm_configs.get(
61
+ rhythm_pattern,
62
+ self.rhythm_configs["calm"] # Default to calm if pattern not found
63
+ )
64
+
65
+ # Symbolic mapping (for future use in SymphAI core)
66
+ self.symbolic_mapping = {
67
+ "calm": "Resonating in the Circle Archetype: completion, wholeness, presence",
68
+ "active": "Resonating in the Spiral Archetype: flow, transition, emergence",
69
+ "focused": "Resonating in the Triangle Archetype: clarity, direction, purpose",
70
+ "relaxed": "Resonating in the Wave Archetype: fluidity, acceptance, surrender"
71
+ }
72
+
73
+ def _generate_base_wave(self, duration):
74
+ """Generate the base carrier wave"""
75
+ t = np.linspace(0, duration, int(self.sample_rate * duration), endpoint=False)
76
+ return t, np.sin(2 * np.pi * self.base_freq * t)
77
+
78
+ def _apply_sine_modulation(self, t, carrier):
79
+ """Apply sine wave modulation"""
80
+ mod_freq = self.config["mod_freq"]
81
+ mod_depth = self.config["mod_depth"]
82
+
83
+ # Create modulation envelope
84
+ mod_env = 1.0 + mod_depth * np.sin(2 * np.pi * mod_freq * t + self.config["phase_shift"])
85
+
86
+ # Apply modulation
87
+ return carrier * mod_env
88
+
89
+ def _apply_pulse_modulation(self, t, carrier):
90
+ """Apply pulse modulation"""
91
+ mod_freq = self.config["mod_freq"]
92
+ mod_depth = self.config["mod_depth"]
93
+ pulse_width = self.config["pulse_width"]
94
+
95
+ # Create pulse modulation envelope
96
+ pulse = signal.square(2 * np.pi * mod_freq * t, duty=pulse_width)
97
+ mod_env = 1.0 + mod_depth * pulse
98
+
99
+ # Apply modulation
100
+ return carrier * mod_env
101
+
102
+ def _apply_chirp_modulation(self, t, carrier):
103
+ """Apply frequency chirp modulation"""
104
+ mod_depth = self.config["mod_depth"]
105
+
106
+ # Create chirp modulation with frequency that increases with time
107
+ start_freq = self.base_freq * (1 - mod_depth/2)
108
+ end_freq = self.base_freq * (1 + mod_depth/2)
109
+
110
+ # Linear chirp
111
+ chirp = signal.chirp(t, start_freq, t[-1], end_freq)
112
+
113
+ # Apply modulation
114
+ return chirp * carrier
115
+
116
+ def _apply_harmonics(self, t, wave):
117
+ """Apply harmonic overtones to enrich the sound"""
118
+ harmonics = self.config["harmonics"]
119
+ rich_wave = np.zeros_like(wave)
120
+
121
+ for i, harmonic_amp in enumerate(harmonics):
122
+ harmonic_freq = self.base_freq * (i + 1)
123
+ rich_wave += harmonic_amp * np.sin(2 * np.pi * harmonic_freq * t)
124
+
125
+ # Normalize
126
+ rich_wave = rich_wave / np.max(np.abs(rich_wave))
127
+ return rich_wave
128
+
129
+ def generate_modulated_wave(self, duration):
130
+ """
131
+ Generate modulated audio wave based on current settings
132
+
133
+ Args:
134
+ duration (float): Duration of audio in seconds
135
+
136
+ Returns:
137
+ numpy.ndarray: The modulated audio waveform
138
+ """
139
+ t, carrier = self._generate_base_wave(duration)
140
+
141
+ # Apply the selected modulation type
142
+ if self.modulation_type == "sine":
143
+ modulated = self._apply_sine_modulation(t, carrier)
144
+ elif self.modulation_type == "pulse":
145
+ modulated = self._apply_pulse_modulation(t, carrier)
146
+ elif self.modulation_type == "chirp":
147
+ modulated = self._apply_chirp_modulation(t, carrier)
148
+ else:
149
+ modulated = carrier # Default to unmodulated carrier
150
+
151
+ # Apply harmonics for richer sound
152
+ enriched = self._apply_harmonics(t, modulated)
153
+
154
+ # Normalize to prevent clipping
155
+ normalized = 0.8 * enriched / np.max(np.abs(enriched))
156
+
157
+ return normalized
158
+
159
+ def visualize_waveform(self, duration):
160
+ """
161
+ Generate visualization of the modulated waveform
162
+
163
+ Args:
164
+ duration (float): Duration of audio in seconds
165
+
166
+ Returns:
167
+ matplotlib.figure.Figure: Figure containing the waveform visualization
168
+ """
169
+ # Generate a shorter segment for visualization
170
+ t = np.linspace(0, min(duration, 2), int(self.sample_rate * min(duration, 2)), endpoint=False)
171
+
172
+ # Generate modulated wave for plotting
173
+ modulated = self.generate_modulated_wave(min(duration, 2))
174
+
175
+ # Create visualization
176
+ fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8))
177
+
178
+ # Plot time domain
179
+ ax1.plot(t[:1000], modulated[:1000])
180
+ ax1.set_title(f'Rhythma Modulated Waveform: {self.rhythm_pattern} ({self.modulation_type})')
181
+ ax1.set_xlabel('Time (s)')
182
+ ax1.set_ylabel('Amplitude')
183
+
184
+ # Plot frequency domain (spectrogram)
185
+ f, t, Sxx = signal.spectrogram(modulated, self.sample_rate)
186
+ ax2.pcolormesh(t, f[:500], Sxx[:500], shading='gouraud')
187
+ ax2.set_ylabel('Frequency (Hz)')
188
+ ax2.set_xlabel('Time (s)')
189
+ ax2.set_title('Spectrogram')
190
+
191
+ plt.tight_layout()
192
+
193
+ # Add symbolic interpretation
194
+ symbolic_text = self.symbolic_mapping.get(self.rhythm_pattern, "")
195
+ fig.text(0.5, 0.01, symbolic_text, ha='center', fontsize=10, style='italic')
196
+
197
+ return fig
198
+
199
+ def get_symbolic_interpretation(self):
200
+ """Return the symbolic interpretation of the current rhythm pattern"""
201
+ return self.symbolic_mapping.get(self.rhythm_pattern, "Unknown pattern")