cycdp 0.1.1__cp312-cp312-macosx_11_0_arm64.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.
cycdp/_core.pyi ADDED
@@ -0,0 +1,1049 @@
1
+ """Type stubs for cycdp._core Cython extension module."""
2
+
3
+ from typing import Sequence, overload
4
+
5
+ # Type alias for buffer-like objects (numpy arrays, array.array('f'), memoryview, etc.)
6
+ # In practice, any object supporting the buffer protocol with float32 data
7
+ from typing import Protocol, runtime_checkable
8
+
9
+ @runtime_checkable
10
+ class BufferLike(Protocol):
11
+ """Protocol for objects supporting the buffer protocol with float32 data."""
12
+ def __buffer__(self, flags: int) -> memoryview: ...
13
+
14
+ # =============================================================================
15
+ # Constants
16
+ # =============================================================================
17
+
18
+ FLAG_NONE: int
19
+ FLAG_CLIP: int
20
+
21
+ # Waveform types for synth_wave
22
+ WAVE_SINE: int
23
+ WAVE_SQUARE: int
24
+ WAVE_SAW: int
25
+ WAVE_RAMP: int
26
+ WAVE_TRIANGLE: int
27
+
28
+ # Scramble modes
29
+ SCRAMBLE_SHUFFLE: int
30
+ SCRAMBLE_REVERSE: int
31
+ SCRAMBLE_SIZE_UP: int
32
+ SCRAMBLE_SIZE_DOWN: int
33
+ SCRAMBLE_LEVEL_UP: int
34
+ SCRAMBLE_LEVEL_DOWN: int
35
+
36
+ # =============================================================================
37
+ # Exception
38
+ # =============================================================================
39
+
40
+ class CDPError(Exception):
41
+ """Exception raised for CDP library errors."""
42
+
43
+ code: int
44
+ def __init__(self, code: int, message: str) -> None: ...
45
+
46
+ # =============================================================================
47
+ # Utility functions
48
+ # =============================================================================
49
+
50
+ def version() -> str:
51
+ """Get CDP library version string."""
52
+ ...
53
+
54
+ def gain_to_db(gain: float) -> float:
55
+ """Convert linear gain to decibels."""
56
+ ...
57
+
58
+ def db_to_gain(db: float) -> float:
59
+ """Convert decibels to linear gain."""
60
+ ...
61
+
62
+ # =============================================================================
63
+ # Classes
64
+ # =============================================================================
65
+
66
+ class Context:
67
+ """CDP processing context."""
68
+ def __init__(self) -> None: ...
69
+ def get_error(self) -> int:
70
+ """Get last error code."""
71
+ ...
72
+ def get_error_message(self) -> str:
73
+ """Get last error message."""
74
+ ...
75
+ def clear_error(self) -> None:
76
+ """Clear error state."""
77
+ ...
78
+
79
+ class Buffer:
80
+ """CDP audio buffer with Python buffer protocol support."""
81
+
82
+ @staticmethod
83
+ def create(frame_count: int, channels: int = 1, sample_rate: int = 44100) -> Buffer:
84
+ """Create a new buffer with allocated memory."""
85
+ ...
86
+
87
+ @staticmethod
88
+ def from_memoryview(
89
+ samples: BufferLike, channels: int = 1, sample_rate: int = 44100
90
+ ) -> Buffer:
91
+ """Create a buffer by copying from a memoryview."""
92
+ ...
93
+
94
+ def to_list(self) -> list[float]:
95
+ """Convert buffer to Python list."""
96
+ ...
97
+
98
+ def to_bytes(self) -> bytes:
99
+ """Convert buffer to bytes (raw float32 data)."""
100
+ ...
101
+
102
+ @property
103
+ def sample_count(self) -> int: ...
104
+ @property
105
+ def frame_count(self) -> int: ...
106
+ @property
107
+ def channels(self) -> int: ...
108
+ @property
109
+ def sample_rate(self) -> int: ...
110
+ def __len__(self) -> int: ...
111
+ def __getitem__(self, index: int) -> float: ...
112
+ def __setitem__(self, index: int, value: float) -> None: ...
113
+ def clear(self) -> None:
114
+ """Set all samples to zero."""
115
+ ...
116
+
117
+ # =============================================================================
118
+ # Low-level functions (work with Buffer objects)
119
+ # =============================================================================
120
+
121
+ def apply_gain(ctx: Context, buf: Buffer, gain: float, clip: bool = False) -> None:
122
+ """Apply gain to buffer (in-place)."""
123
+ ...
124
+
125
+ def apply_gain_db(
126
+ ctx: Context, buf: Buffer, gain_db: float, clip: bool = False
127
+ ) -> None:
128
+ """Apply gain in dB to buffer (in-place)."""
129
+ ...
130
+
131
+ def apply_normalize(ctx: Context, buf: Buffer, target_level: float = 1.0) -> None:
132
+ """Normalize buffer to target level (in-place)."""
133
+ ...
134
+
135
+ def apply_normalize_db(ctx: Context, buf: Buffer, target_db: float = 0.0) -> None:
136
+ """Normalize buffer to target dB level (in-place)."""
137
+ ...
138
+
139
+ def apply_phase_invert(ctx: Context, buf: Buffer) -> None:
140
+ """Invert phase of buffer (in-place)."""
141
+ ...
142
+
143
+ def get_peak(ctx: Context, buf: Buffer) -> tuple[float, int]:
144
+ """Find peak level in buffer. Returns (level, frame_position)."""
145
+ ...
146
+
147
+ # =============================================================================
148
+ # High-level functions (accept any float32 buffer via memoryview)
149
+ # =============================================================================
150
+
151
+ def gain(
152
+ samples: BufferLike,
153
+ gain_factor: float = 1.0,
154
+ sample_rate: int = 44100,
155
+ clip: bool = False,
156
+ ) -> Buffer:
157
+ """Apply gain to audio samples."""
158
+ ...
159
+
160
+ def gain_db(
161
+ samples: BufferLike, db: float = 0.0, sample_rate: int = 44100, clip: bool = False
162
+ ) -> Buffer:
163
+ """Apply gain in decibels to audio samples."""
164
+ ...
165
+
166
+ def normalize(
167
+ samples: BufferLike, target: float = 1.0, sample_rate: int = 44100
168
+ ) -> Buffer:
169
+ """Normalize audio to target peak level."""
170
+ ...
171
+
172
+ def normalize_db(
173
+ samples: BufferLike, target_db: float = 0.0, sample_rate: int = 44100
174
+ ) -> Buffer:
175
+ """Normalize audio to target peak level in dB."""
176
+ ...
177
+
178
+ @overload
179
+ def phase_invert(samples: BufferLike, sample_rate: int = 44100) -> Buffer:
180
+ """Invert phase of audio samples (high-level)."""
181
+ ...
182
+
183
+ @overload
184
+ def phase_invert(buf: Buffer) -> Buffer:
185
+ """Invert phase of buffer (CDP lib version)."""
186
+ ...
187
+
188
+ def peak(samples: BufferLike, sample_rate: int = 44100) -> tuple[float, int]:
189
+ """Find peak level in audio samples. Returns (peak_level, sample_position)."""
190
+ ...
191
+
192
+ # =============================================================================
193
+ # File I/O
194
+ # =============================================================================
195
+
196
+ def read_file(path: str) -> Buffer:
197
+ """Read an audio file into a Buffer."""
198
+ ...
199
+
200
+ def write_file(path: str, buf: Buffer, format: str = "float") -> None:
201
+ """Write a Buffer to an audio file."""
202
+ ...
203
+
204
+ # =============================================================================
205
+ # Spatial/panning
206
+ # =============================================================================
207
+
208
+ def pan(buf: Buffer, position: float = 0.0) -> Buffer:
209
+ """Pan a mono buffer to stereo with a static pan position."""
210
+ ...
211
+
212
+ def pan_envelope(buf: Buffer, points: list[tuple[float, float]]) -> Buffer:
213
+ """Pan a mono buffer to stereo with time-varying position."""
214
+ ...
215
+
216
+ def mirror(buf: Buffer) -> Buffer:
217
+ """Mirror (swap) left and right channels of a stereo buffer."""
218
+ ...
219
+
220
+ def narrow(buf: Buffer, width: float = 1.0) -> Buffer:
221
+ """Narrow or widen stereo image."""
222
+ ...
223
+
224
+ # =============================================================================
225
+ # Mixing
226
+ # =============================================================================
227
+
228
+ def mix2(a: Buffer, b: Buffer, gain_a: float = 1.0, gain_b: float = 1.0) -> Buffer:
229
+ """Mix two buffers together with optional gains."""
230
+ ...
231
+
232
+ def mix(buffers: list[Buffer], gains: list[float] | None = None) -> Buffer:
233
+ """Mix multiple buffers together with optional gains."""
234
+ ...
235
+
236
+ # =============================================================================
237
+ # Buffer utilities
238
+ # =============================================================================
239
+
240
+ def reverse(buf: Buffer) -> Buffer:
241
+ """Reverse audio buffer."""
242
+ ...
243
+
244
+ def fade_in(buf: Buffer, duration: float, curve: str = "linear") -> Buffer:
245
+ """Apply fade in to buffer (in-place)."""
246
+ ...
247
+
248
+ def fade_out(buf: Buffer, duration: float, curve: str = "linear") -> Buffer:
249
+ """Apply fade out to buffer (in-place)."""
250
+ ...
251
+
252
+ def concat(buffers: list[Buffer]) -> Buffer:
253
+ """Concatenate multiple buffers into one."""
254
+ ...
255
+
256
+ # =============================================================================
257
+ # Channel operations
258
+ # =============================================================================
259
+
260
+ def to_mono(buf: Buffer) -> Buffer:
261
+ """Convert multi-channel buffer to mono by averaging all channels."""
262
+ ...
263
+
264
+ def to_stereo(buf: Buffer) -> Buffer:
265
+ """Convert mono buffer to stereo by duplicating the channel."""
266
+ ...
267
+
268
+ def extract_channel(buf: Buffer, channel: int) -> Buffer:
269
+ """Extract a single channel from a multi-channel buffer."""
270
+ ...
271
+
272
+ def merge_channels(left: Buffer, right: Buffer) -> Buffer:
273
+ """Merge two mono buffers into a stereo buffer."""
274
+ ...
275
+
276
+ def split_channels(buf: Buffer) -> list[Buffer]:
277
+ """Split a multi-channel buffer into separate mono buffers."""
278
+ ...
279
+
280
+ def interleave(buffers: list[Buffer]) -> Buffer:
281
+ """Interleave multiple mono buffers into a multi-channel buffer."""
282
+ ...
283
+
284
+ # =============================================================================
285
+ # Spectral processing
286
+ # =============================================================================
287
+
288
+ def time_stretch(
289
+ buf: Buffer, factor: float, fft_size: int = 1024, overlap: int = 3
290
+ ) -> Buffer:
291
+ """Time-stretch audio without changing pitch."""
292
+ ...
293
+
294
+ def spectral_blur(buf: Buffer, blur_time: float, fft_size: int = 1024) -> Buffer:
295
+ """Blur/smear the spectrum over time."""
296
+ ...
297
+
298
+ def modify_speed(buf: Buffer, speed_factor: float) -> Buffer:
299
+ """Change playback speed (affects both time and pitch)."""
300
+ ...
301
+
302
+ def pitch_shift(buf: Buffer, semitones: float, fft_size: int = 1024) -> Buffer:
303
+ """Shift pitch without changing duration."""
304
+ ...
305
+
306
+ def spectral_shift(buf: Buffer, shift_hz: float, fft_size: int = 1024) -> Buffer:
307
+ """Shift spectrum up or down by a fixed frequency."""
308
+ ...
309
+
310
+ def spectral_stretch(
311
+ buf: Buffer, max_stretch: float, fft_size: int = 1024, mode: int = 0
312
+ ) -> Buffer:
313
+ """Stretch or compress the spectrum."""
314
+ ...
315
+
316
+ def filter_lowpass(
317
+ buf: Buffer, cutoff_freq: float, fft_size: int = 1024, rolloff: float = 1.0
318
+ ) -> Buffer:
319
+ """Apply low-pass filter."""
320
+ ...
321
+
322
+ def filter_highpass(
323
+ buf: Buffer, cutoff_freq: float, fft_size: int = 1024, rolloff: float = 1.0
324
+ ) -> Buffer:
325
+ """Apply high-pass filter."""
326
+ ...
327
+
328
+ def filter_bandpass(
329
+ buf: Buffer,
330
+ low_freq: float,
331
+ high_freq: float,
332
+ fft_size: int = 1024,
333
+ rolloff: float = 1.0,
334
+ ) -> Buffer:
335
+ """Apply band-pass filter."""
336
+ ...
337
+
338
+ def filter_notch(
339
+ buf: Buffer,
340
+ center_freq: float,
341
+ width_hz: float,
342
+ fft_size: int = 1024,
343
+ depth: float = 1.0,
344
+ ) -> Buffer:
345
+ """Apply notch (band-reject) filter."""
346
+ ...
347
+
348
+ # =============================================================================
349
+ # Dynamics and effects
350
+ # =============================================================================
351
+
352
+ def gate(
353
+ buf: Buffer,
354
+ threshold_db: float,
355
+ attack_ms: float = 1.0,
356
+ hold_ms: float = 50.0,
357
+ release_ms: float = 50.0,
358
+ ) -> Buffer:
359
+ """Apply noise gate."""
360
+ ...
361
+
362
+ def bitcrush(buf: Buffer, bit_depth: int = 8, downsample: int = 1) -> Buffer:
363
+ """Apply bit depth reduction and downsampling."""
364
+ ...
365
+
366
+ def ring_mod(buf: Buffer, freq: float, mix: float = 1.0) -> Buffer:
367
+ """Apply ring modulation."""
368
+ ...
369
+
370
+ def delay(
371
+ buf: Buffer, delay_ms: float, feedback: float = 0.3, mix: float = 0.5
372
+ ) -> Buffer:
373
+ """Apply delay effect."""
374
+ ...
375
+
376
+ def chorus(
377
+ buf: Buffer, rate: float = 1.5, depth_ms: float = 5.0, mix: float = 0.5
378
+ ) -> Buffer:
379
+ """Apply chorus effect."""
380
+ ...
381
+
382
+ def flanger(
383
+ buf: Buffer,
384
+ rate: float = 0.5,
385
+ depth_ms: float = 3.0,
386
+ feedback: float = 0.7,
387
+ mix: float = 0.5,
388
+ ) -> Buffer:
389
+ """Apply flanger effect."""
390
+ ...
391
+
392
+ # =============================================================================
393
+ # EQ and dynamics
394
+ # =============================================================================
395
+
396
+ def eq_parametric(
397
+ buf: Buffer, center_freq: float, gain_db: float, q: float = 1.0
398
+ ) -> Buffer:
399
+ """Apply parametric EQ band."""
400
+ ...
401
+
402
+ def envelope_follow(
403
+ buf: Buffer, attack_ms: float = 10.0, release_ms: float = 100.0, mode: str = "peak"
404
+ ) -> Buffer:
405
+ """Extract amplitude envelope from audio."""
406
+ ...
407
+
408
+ def envelope_apply(buf: Buffer, envelope: Buffer, depth: float = 1.0) -> Buffer:
409
+ """Apply envelope to audio."""
410
+ ...
411
+
412
+ def compressor(
413
+ buf: Buffer,
414
+ threshold_db: float = -20.0,
415
+ ratio: float = 4.0,
416
+ attack_ms: float = 10.0,
417
+ release_ms: float = 100.0,
418
+ makeup_db: float = 0.0,
419
+ ) -> Buffer:
420
+ """Apply dynamic range compression."""
421
+ ...
422
+
423
+ def limiter(
424
+ buf: Buffer,
425
+ threshold_db: float = -0.1,
426
+ attack_ms: float = 0.1,
427
+ release_ms: float = 50.0,
428
+ ) -> Buffer:
429
+ """Apply peak limiting."""
430
+ ...
431
+
432
+ # =============================================================================
433
+ # Envelope operations
434
+ # =============================================================================
435
+
436
+ def dovetail(
437
+ buf: Buffer, fade_in_dur: float, fade_out_dur: float, fade_type: int = 0
438
+ ) -> Buffer:
439
+ """Apply dovetail fades."""
440
+ ...
441
+
442
+ def tremolo(buf: Buffer, freq: float, depth: float, gain: float = 1.0) -> Buffer:
443
+ """Apply tremolo effect."""
444
+ ...
445
+
446
+ def attack(buf: Buffer, attack_gain: float, attack_time: float) -> Buffer:
447
+ """Modify attack transient."""
448
+ ...
449
+
450
+ # =============================================================================
451
+ # Distortion operations
452
+ # =============================================================================
453
+
454
+ def distort_overload(buf: Buffer, clip_level: float, depth: float = 0.5) -> Buffer:
455
+ """Apply overload/saturation distortion."""
456
+ ...
457
+
458
+ def distort_reverse(buf: Buffer, cycle_count: int) -> Buffer:
459
+ """Apply reverse distortion effect."""
460
+ ...
461
+
462
+ def distort_fractal(buf: Buffer, scaling: float, loudness: float = 1.0) -> Buffer:
463
+ """Apply fractal distortion."""
464
+ ...
465
+
466
+ def distort_shuffle(buf: Buffer, chunk_count: int, seed: int = 0) -> Buffer:
467
+ """Apply shuffle distortion."""
468
+ ...
469
+
470
+ def distort_cut(
471
+ buf: Buffer, cycle_count: int = 4, cycle_step: int = 4, decay: float = 0.9
472
+ ) -> Buffer:
473
+ """Waveset cut with decaying envelope."""
474
+ ...
475
+
476
+ def distort_mark(
477
+ buf: Buffer, markers: Sequence[float], unit_ms: float = 10.0, interp_ms: float = 5.0
478
+ ) -> Buffer:
479
+ """Interpolate wavesets at time markers."""
480
+ ...
481
+
482
+ def distort_repeat(
483
+ buf: Buffer, multiplier: int = 2, cycle_count: int = 1, skip: int = 0
484
+ ) -> Buffer:
485
+ """Time-stretch by repeating wavecycles."""
486
+ ...
487
+
488
+ def distort_shift(
489
+ buf: Buffer, group_size: int = 1, shift: int = 1, mode: int = 0
490
+ ) -> Buffer:
491
+ """Shift/swap half-wavecycle groups."""
492
+ ...
493
+
494
+ def distort_warp(
495
+ buf: Buffer, warp: float = 0.001, mode: int = 0, waveset_count: int = 1
496
+ ) -> Buffer:
497
+ """Progressive warp distortion with sample folding."""
498
+ ...
499
+
500
+ # =============================================================================
501
+ # Reverb
502
+ # =============================================================================
503
+
504
+ def reverb(
505
+ buf: Buffer,
506
+ mix: float = 0.5,
507
+ decay_time: float = 2.0,
508
+ damping: float = 0.5,
509
+ room_size: float = 0.5,
510
+ ) -> Buffer:
511
+ """Apply reverb effect."""
512
+ ...
513
+
514
+ # =============================================================================
515
+ # Granular operations
516
+ # =============================================================================
517
+
518
+ def brassage(
519
+ buf: Buffer,
520
+ velocity: float = 1.0,
521
+ density: float = 1.0,
522
+ grainsize_ms: float = 50.0,
523
+ pitch_shift: float = 0.0,
524
+ scatter: float = 0.0,
525
+ ) -> Buffer:
526
+ """Apply granular brassage."""
527
+ ...
528
+
529
+ def freeze(
530
+ buf: Buffer,
531
+ start_time: float,
532
+ end_time: float,
533
+ grainsize_ms: float = 50.0,
534
+ density: float = 1.0,
535
+ duration: float = 5.0,
536
+ ) -> Buffer:
537
+ """Granular freeze at position."""
538
+ ...
539
+
540
+ def grain_cloud(
541
+ buf: Buffer,
542
+ gate: float = 0.1,
543
+ grainsize_ms: float = 50.0,
544
+ density: float = 1.0,
545
+ duration: float = 5.0,
546
+ ) -> Buffer:
547
+ """Grain cloud generation from amplitude-detected grains."""
548
+ ...
549
+
550
+ def grain_extend(
551
+ buf: Buffer, grainsize_ms: float = 15.0, trough: float = 0.3, repeats: int = 2
552
+ ) -> Buffer:
553
+ """Extend duration using grain repetition."""
554
+ ...
555
+
556
+ def texture_simple(
557
+ buf: Buffer,
558
+ duration: float = 5.0,
559
+ density: float = 5.0,
560
+ grainsize_ms: float = 50.0,
561
+ scatter: float = 0.5,
562
+ ) -> Buffer:
563
+ """Simple texture synthesis."""
564
+ ...
565
+
566
+ def texture_multi(
567
+ buf: Buffer,
568
+ duration: float = 5.0,
569
+ density: float = 2.0,
570
+ grainsize_ms: float = 50.0,
571
+ num_layers: int = 4,
572
+ pitch_spread: float = 0.0,
573
+ ) -> Buffer:
574
+ """Multi-layer grouped texture synthesis."""
575
+ ...
576
+
577
+ # =============================================================================
578
+ # Extended granular operations
579
+ # =============================================================================
580
+
581
+ def grain_reorder(
582
+ buf: Buffer,
583
+ order: list[int] | None = None,
584
+ gate: float = 0.1,
585
+ grainsize_ms: float = 50.0,
586
+ ) -> Buffer:
587
+ """Reorder detected grains."""
588
+ ...
589
+
590
+ def grain_rerhythm(
591
+ buf: Buffer,
592
+ times: list[float] | None = None,
593
+ ratios: list[float] | None = None,
594
+ gate: float = 0.1,
595
+ grainsize_ms: float = 50.0,
596
+ ) -> Buffer:
597
+ """Change timing/rhythm of grains."""
598
+ ...
599
+
600
+ def grain_reverse(buf: Buffer, gate: float = 0.1, grainsize_ms: float = 50.0) -> Buffer:
601
+ """Reverse individual grains in place."""
602
+ ...
603
+
604
+ def grain_timewarp(
605
+ buf: Buffer,
606
+ stretch: float = 1.0,
607
+ stretch_curve: list[tuple[float, float]] | None = None,
608
+ gate: float = 0.1,
609
+ grainsize_ms: float = 50.0,
610
+ ) -> Buffer:
611
+ """Time-stretch/compress grain spacing."""
612
+ ...
613
+
614
+ def grain_repitch(
615
+ buf: Buffer,
616
+ pitch_semitones: float = 0.0,
617
+ pitch_curve: list[tuple[float, float]] | None = None,
618
+ gate: float = 0.1,
619
+ grainsize_ms: float = 50.0,
620
+ ) -> Buffer:
621
+ """Pitch-shift grains with interpolation."""
622
+ ...
623
+
624
+ def grain_position(
625
+ buf: Buffer,
626
+ positions: list[float] | None = None,
627
+ duration: float = 0.0,
628
+ gate: float = 0.1,
629
+ grainsize_ms: float = 50.0,
630
+ ) -> Buffer:
631
+ """Reposition grains in stereo field."""
632
+ ...
633
+
634
+ def grain_omit(
635
+ buf: Buffer,
636
+ keep: int = 1,
637
+ out_of: int = 2,
638
+ gate: float = 0.1,
639
+ grainsize_ms: float = 50.0,
640
+ ) -> Buffer:
641
+ """Probabilistically omit grains."""
642
+ ...
643
+
644
+ def grain_duplicate(
645
+ buf: Buffer, repeats: int = 2, gate: float = 0.1, grainsize_ms: float = 50.0
646
+ ) -> Buffer:
647
+ """Duplicate grains with variations."""
648
+ ...
649
+
650
+ # =============================================================================
651
+ # Spectral operations
652
+ # =============================================================================
653
+
654
+ def spectral_focus(
655
+ buf: Buffer,
656
+ center_freq: float = 1000.0,
657
+ bandwidth: float = 500.0,
658
+ gain: float = 2.0,
659
+ fft_size: int = 1024,
660
+ ) -> Buffer:
661
+ """Focus on frequency region."""
662
+ ...
663
+
664
+ def spectral_hilite(
665
+ buf: Buffer, threshold_db: float = -20.0, gain: float = 2.0, fft_size: int = 1024
666
+ ) -> Buffer:
667
+ """Highlight frequency region."""
668
+ ...
669
+
670
+ def spectral_fold(
671
+ buf: Buffer, fold_freq: float = 2000.0, fft_size: int = 1024
672
+ ) -> Buffer:
673
+ """Fold spectrum around frequency."""
674
+ ...
675
+
676
+ def spectral_clean(
677
+ buf: Buffer, threshold_db: float = -40.0, fft_size: int = 1024
678
+ ) -> Buffer:
679
+ """Remove spectral noise."""
680
+ ...
681
+
682
+ # =============================================================================
683
+ # Experimental/Chaos
684
+ # =============================================================================
685
+
686
+ def strange(
687
+ buf: Buffer, chaos_amount: float = 0.5, rate: float = 2.0, mode: int = 0
688
+ ) -> Buffer:
689
+ """Strange attractor transformation."""
690
+ ...
691
+
692
+ def brownian(
693
+ buf: Buffer, step_size: float = 0.1, smoothing: float = 0.9, mode: int = 0
694
+ ) -> Buffer:
695
+ """Brownian motion transformation."""
696
+ ...
697
+
698
+ def crystal(
699
+ buf: Buffer, density: float = 50.0, decay: float = 0.5, pitch_variance: float = 0.1
700
+ ) -> Buffer:
701
+ """Crystal growth patterns."""
702
+ ...
703
+
704
+ def fractal(
705
+ buf: Buffer, depth: int = 3, pitch_ratio: float = 0.5, amp_decay: float = 0.7
706
+ ) -> Buffer:
707
+ """Fractal transformation."""
708
+ ...
709
+
710
+ def quirk(
711
+ buf: Buffer, probability: float = 0.3, intensity: float = 0.5, seed: int = 0
712
+ ) -> Buffer:
713
+ """Quirky transformation."""
714
+ ...
715
+
716
+ def chirikov(
717
+ buf: Buffer, k_param: float = 2.0, mod_depth: float = 0.5, rate: float = 10.0
718
+ ) -> Buffer:
719
+ """Chirikov map transformation."""
720
+ ...
721
+
722
+ def cantor(
723
+ buf: Buffer, depth: int = 4, duty_cycle: float = 0.5, fade_ms: float = 5.0
724
+ ) -> Buffer:
725
+ """Cantor set transformation."""
726
+ ...
727
+
728
+ def cascade(
729
+ buf: Buffer,
730
+ num_echoes: int = 6,
731
+ delay_ms: float = 100.0,
732
+ decay: float = 0.7,
733
+ pitch_shift: float = -2.0,
734
+ ) -> Buffer:
735
+ """Cascade transformation."""
736
+ ...
737
+
738
+ def fracture(
739
+ buf: Buffer, fragment_ms: float = 50.0, gap_ratio: float = 0.5, scatter: float = 0.3
740
+ ) -> Buffer:
741
+ """Fracture transformation."""
742
+ ...
743
+
744
+ def tesselate(
745
+ buf: Buffer, tile_ms: float = 50.0, pattern: int = 1, overlap: float = 0.5
746
+ ) -> Buffer:
747
+ """Tesselation transformation."""
748
+ ...
749
+
750
+ # =============================================================================
751
+ # Morphing/Cross-synthesis
752
+ # =============================================================================
753
+
754
+ def morph(
755
+ buf1: Buffer, buf2: Buffer, amount: float = 0.5, fft_size: int = 1024
756
+ ) -> Buffer:
757
+ """Spectral morph between sounds."""
758
+ ...
759
+
760
+ def morph_glide(buf1: Buffer, buf2: Buffer, fft_size: int = 1024) -> Buffer:
761
+ """Gliding morph over time."""
762
+ ...
763
+
764
+ def cross_synth(
765
+ buf1: Buffer, buf2: Buffer, fft_size: int = 1024, mode: int = 0
766
+ ) -> Buffer:
767
+ """Cross-synthesis (vocoder-like)."""
768
+ ...
769
+
770
+ def morph_glide_native(buf1: Buffer, buf2: Buffer, fft_size: int = 1024) -> Buffer:
771
+ """Native CDP specglide wrapper."""
772
+ ...
773
+
774
+ def morph_bridge_native(
775
+ buf1: Buffer, buf2: Buffer, fft_size: int = 1024, interp_count: int = 8
776
+ ) -> Buffer:
777
+ """Native CDP specbridge wrapper."""
778
+ ...
779
+
780
+ def morph_native(
781
+ buf1: Buffer, buf2: Buffer, fft_size: int = 1024, interp_count: int = 8
782
+ ) -> Buffer:
783
+ """Native CDP specmorph wrapper."""
784
+ ...
785
+
786
+ # =============================================================================
787
+ # Analysis
788
+ # =============================================================================
789
+
790
+ def pitch(
791
+ buf: Buffer,
792
+ min_freq: float = 50.0,
793
+ max_freq: float = 2000.0,
794
+ frame_size: int = 2048,
795
+ hop_size: int = 512,
796
+ ) -> list[tuple[float, float]]:
797
+ """Extract pitch data."""
798
+ ...
799
+
800
+ def formants(
801
+ buf: Buffer, lpc_order: int = 12, frame_size: int = 1024, hop_size: int = 256
802
+ ) -> list[list[tuple[float, float]]]:
803
+ """Extract formant data."""
804
+ ...
805
+
806
+ def get_partials(
807
+ buf: Buffer,
808
+ min_amp_db: float = -60.0,
809
+ max_partials: int = 100,
810
+ fft_size: int = 4096,
811
+ ) -> list[tuple[float, float, float]]:
812
+ """Extract partial/harmonic data."""
813
+ ...
814
+
815
+ # =============================================================================
816
+ # Playback/Time manipulation
817
+ # =============================================================================
818
+
819
+ def zigzag(buf: Buffer, times: Sequence[float], splice_ms: float = 15.0) -> Buffer:
820
+ """Alternating forward/backward playback through time points."""
821
+ ...
822
+
823
+ def iterate(
824
+ buf: Buffer,
825
+ repeats: int = 4,
826
+ delay: float = 0.5,
827
+ pitch_shift: float = 0.0,
828
+ gain_decay: float = 0.9,
829
+ ) -> Buffer:
830
+ """Repeat audio with pitch shift and gain decay variations."""
831
+ ...
832
+
833
+ def stutter(
834
+ buf: Buffer,
835
+ segment_ms: float = 100.0,
836
+ duration: float = 5.0,
837
+ silence_ratio: float = 0.5,
838
+ ) -> Buffer:
839
+ """Segment-based stuttering with silence inserts."""
840
+ ...
841
+
842
+ def bounce(
843
+ buf: Buffer,
844
+ bounces: int = 8,
845
+ initial_delay: float = 0.5,
846
+ decay: float = 0.7,
847
+ pitch_drop: float = 0.0,
848
+ ) -> Buffer:
849
+ """Bouncing ball effect with accelerating repeats."""
850
+ ...
851
+
852
+ def drunk(
853
+ buf: Buffer,
854
+ duration: float = 5.0,
855
+ step_ms: float = 100.0,
856
+ max_step: float = 0.1,
857
+ splice_ms: float = 10.0,
858
+ ) -> Buffer:
859
+ """Random 'drunk walk' navigation through audio."""
860
+ ...
861
+
862
+ def loop(
863
+ buf: Buffer,
864
+ start: float = 0.0,
865
+ length_ms: float = 500.0,
866
+ repeats: int = 4,
867
+ crossfade_ms: float = 10.0,
868
+ ) -> Buffer:
869
+ """Loop a section with crossfades and variations."""
870
+ ...
871
+
872
+ def retime(
873
+ buf: Buffer, ratio: float = 1.0, grain_ms: float = 50.0, overlap: float = 0.5
874
+ ) -> Buffer:
875
+ """Time-domain time stretch/compress (TDOLA)."""
876
+ ...
877
+
878
+ def scramble(buf: Buffer, mode: int = 0, group_size: int = 2, seed: int = 0) -> Buffer:
879
+ """Reorder wavesets (shuffle, reverse, by size/level)."""
880
+ ...
881
+
882
+ def splinter(
883
+ buf: Buffer,
884
+ start: float = 0.0,
885
+ duration_ms: float = 50.0,
886
+ repeats: int = 20,
887
+ shrink: float = 0.9,
888
+ ) -> Buffer:
889
+ """Fragmenting effect with shrinking repeats."""
890
+ ...
891
+
892
+ # =============================================================================
893
+ # Spatial effects
894
+ # =============================================================================
895
+
896
+ def spin(
897
+ buf: Buffer, rate: float = 1.0, doppler: float = 0.0, depth: float = 1.0
898
+ ) -> Buffer:
899
+ """Rotate audio around stereo field with optional doppler."""
900
+ ...
901
+
902
+ def rotor(
903
+ buf: Buffer,
904
+ pitch_rate: float = 1.0,
905
+ pitch_depth: float = 2.0,
906
+ amp_rate: float = 1.5,
907
+ amp_depth: float = 0.5,
908
+ ) -> Buffer:
909
+ """Dual-rotation modulation (pitch + amplitude interference)."""
910
+ ...
911
+
912
+ def flutter(
913
+ buf: Buffer, frequency: float = 4.0, depth: float = 1.0, phase: float = 0.0
914
+ ) -> Buffer:
915
+ """Spatial tremolo (loudness modulation alternating L/R)."""
916
+ ...
917
+
918
+ # =============================================================================
919
+ # Synthesis
920
+ # =============================================================================
921
+
922
+ def synth_wave(
923
+ waveform: int = ...,
924
+ frequency: float = 440.0,
925
+ amplitude: float = 0.8,
926
+ duration: float = 1.0,
927
+ sample_rate: int = 44100,
928
+ ) -> Buffer:
929
+ """Generate waveforms (sine, square, saw, ramp, triangle)."""
930
+ ...
931
+
932
+ def synth_noise(
933
+ pink: int = 0,
934
+ amplitude: float = 0.8,
935
+ duration: float = 1.0,
936
+ sample_rate: int = 44100,
937
+ ) -> Buffer:
938
+ """Generate white or pink noise."""
939
+ ...
940
+
941
+ def synth_click(
942
+ tempo: float = 120.0,
943
+ beats_per_bar: int = 4,
944
+ duration: float = 10.0,
945
+ sample_rate: int = 44100,
946
+ ) -> Buffer:
947
+ """Generate click/metronome track."""
948
+ ...
949
+
950
+ def synth_chord(
951
+ midi_notes: Sequence[int],
952
+ amplitude: float = 0.8,
953
+ duration: float = 1.0,
954
+ sample_rate: int = 44100,
955
+ ) -> Buffer:
956
+ """Synthesize chord from MIDI note list."""
957
+ ...
958
+
959
+ # =============================================================================
960
+ # Pitch-synchronous operations (PSOW)
961
+ # =============================================================================
962
+
963
+ def psow_stretch(
964
+ buf: Buffer, stretch_factor: float = 1.0, grain_count: int = 1
965
+ ) -> Buffer:
966
+ """Time-stretch while preserving pitch (PSOLA)."""
967
+ ...
968
+
969
+ def psow_grab(
970
+ buf: Buffer, time: float = 0.0, duration: float = 0.0, grain_count: int = 1
971
+ ) -> Buffer:
972
+ """Extract pitch-synchronous grains from position."""
973
+ ...
974
+
975
+ def psow_dupl(buf: Buffer, repeat_count: int = 2, grain_count: int = 1) -> Buffer:
976
+ """Duplicate grains for time-stretching."""
977
+ ...
978
+
979
+ def psow_interp(grain1: Buffer, grain2: Buffer, interp_count: int = 8) -> Buffer:
980
+ """Interpolate between two grains."""
981
+ ...
982
+
983
+ # =============================================================================
984
+ # FOF extraction and synthesis (FOFEX)
985
+ # =============================================================================
986
+
987
+ def fofex_extract(
988
+ buf: Buffer, time: float, fof_count: int = 1, window: bool = True
989
+ ) -> Buffer:
990
+ """Extract single FOF (pitch-synchronous grain) at time."""
991
+ ...
992
+
993
+ def fofex_extract_all(
994
+ buf: Buffer, fof_count: int = 1, min_level_db: float = 0.0, window: bool = True
995
+ ) -> Buffer:
996
+ """Extract all FOFs to uniform-length bank."""
997
+ ...
998
+
999
+ def fofex_synth(
1000
+ fof_bank: Buffer, duration: float, frequency: float, amplitude: float = 1.0
1001
+ ) -> Buffer:
1002
+ """Synthesize audio from FOFs at target pitch."""
1003
+ ...
1004
+
1005
+ def fofex_repitch(
1006
+ buf: Buffer, pitch_shift: float, preserve_formants: bool = True
1007
+ ) -> Buffer:
1008
+ """Repitch audio with optional formant preservation."""
1009
+ ...
1010
+
1011
+ # =============================================================================
1012
+ # Hover/Constrict/Phase
1013
+ # =============================================================================
1014
+
1015
+ def hover(
1016
+ buf: Buffer,
1017
+ frequency: float = 440.0,
1018
+ location: float = 0.5,
1019
+ duration: float = 5.0,
1020
+ grainsize_ms: float = 50.0,
1021
+ ) -> Buffer:
1022
+ """Zigzag reading at specified frequency for hovering pitch effect."""
1023
+ ...
1024
+
1025
+ def constrict(buf: Buffer, constriction: float = 50.0) -> Buffer:
1026
+ """Shorten or remove silent sections."""
1027
+ ...
1028
+
1029
+ def phase_stereo(buf: Buffer, transfer: float = 1.0) -> Buffer:
1030
+ """Enhance stereo separation via phase subtraction."""
1031
+ ...
1032
+
1033
+ # =============================================================================
1034
+ # Granular texture
1035
+ # =============================================================================
1036
+
1037
+ def wrappage(
1038
+ buf: Buffer,
1039
+ grain_size: float = 50.0,
1040
+ density: float = 1.0,
1041
+ velocity: float = 1.0,
1042
+ pitch: float = 0.0,
1043
+ spread: float = 1.0,
1044
+ jitter: float = 0.1,
1045
+ splice_ms: float = 5.0,
1046
+ duration: float = 0.0,
1047
+ ) -> Buffer:
1048
+ """Granular texture with stereo spatial distribution."""
1049
+ ...