Aluode commited on
Commit
26b31ff
·
verified ·
1 Parent(s): 49286bf

Upload 4 files

Browse files
Files changed (4) hide show
  1. LICENSE +21 -0
  2. README.md +25 -15
  3. app.py +1 -0
  4. requirements.txt +5 -0
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2026 anttiluode
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md CHANGED
@@ -1,15 +1,25 @@
1
- ---
2
- title: BreakSongToPCAModes
3
- emoji: 🌖
4
- colorFrom: gray
5
- colorTo: blue
6
- sdk: gradio
7
- sdk_version: 6.26.0
8
- python_version: '3.12'
9
- app_file: app.py
10
- pinned: false
11
- license: mit
12
- short_description: 'Breaks songs to PCA modes that may be accepted by Suno. '
13
- ---
14
-
15
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Break Song To PCA Modes
3
+ emoji: 🎵
4
+ colorFrom: indigo
5
+ colorTo: purple
6
+ sdk: gradio
7
+ sdk_version: 4.44.0
8
+ app_file: app.py
9
+ pinned: false
10
+ license: mit
11
+ short_description: Decompose audio tracks into PCA modes.
12
+ ---
13
+
14
+ # Break Song To PCA Modes
15
+
16
+ An interactive audio decomposition app that breaks down songs into PCA modes.
17
+
18
+ ## Installation & Local Run
19
+
20
+ ```bash
21
+ git clone [https://huggingface.co/spaces/](https://huggingface.co/spaces/)<your-username>/BreakSongToPCAModes
22
+ cd BreakSongToPCAModes
23
+ pip install -r requirements.txt
24
+ python app.py
25
+ ```
app.py ADDED
@@ -0,0 +1 @@
 
0
  L = (dim - 1) * tau + 1
1
  win = sliding_window_view(x, L)[:, ::tau]
2
  return win[:, ::-1].copy()
3
  """
4
  Returns list of raw PCA mode signals (time domain) of length same as input.
5
  Each mode is a reconstructed time series from one singular vector.
6
  """
7
  # Delay-embed
8
  X = embed(x, dim, tau)
9
  # Normalise rows
10
  a = np.linalg.norm(X, axis=1) + 1e-9
11
  Xv = X / a[:, None]
12
 
13
  # Randomized SVD
14
  U, S, Vt = randomized_svd(Xv, n_components=k, n_iter=5, random_state=0)
15
  W = Vt # shape (k, dim)
16
 
17
  # Project each mode back to original space
18
  Y = Xv @ W.T # activations (T x k)
19
 
20
  raw_modes = []
21
  for i in range(k):
22
  # Reconstruct this mode alone
23
  mode_embedded = Y[:, i:i+1] @ W[i:i+1, :] # (T, dim)
24
  mode_signal = np.real(mode_embedded[:, 0]) * a
25
  raw_modes.append(mode_signal)
26
 
27
  return raw_modes
28
  if file is None:
29
  raise gr.Error("Please upload an audio file.")
30
 
31
  # Load and preprocess
32
  try:
33
  sig, fs = sf.read(file)
34
  except Exception as e:
35
  raise gr.Error(f"Failed to read: {e}")
36
 
37
  if sig.ndim > 1:
38
  sig = np.mean(sig, axis=1)
39
 
40
  # Resample to 16 kHz for speed/consistency
41
  target_sr = 16000
42
  if fs != target_sr:
43
  sig = signal.resample_poly(sig, target_sr, fs)
44
  fs = target_sr
45
 
46
  # Normalise
47
  sig = sig / (np.max(np.abs(sig)) + 1e-9)
48
 
49
  duration = len(sig) / fs
50
  gr.Info(f"Processing {duration:.1f} sec song with dim={dim}, tau={tau}, k={k} ...")
51
 
52
  # Extract raw modes
53
  try:
54
  raw_modes = extract_raw_modes(sig, dim=dim, tau=tau, k=k)
55
  except Exception as e:
56
  raise gr.Error(f"Extraction failed: {e}")
57
 
58
  # Create ZIP with raw mode WAVs
59
  temp_dir = tempfile.mkdtemp()
60
  for i, mode in enumerate(raw_modes):
61
  sf.write(os.path.join(temp_dir, f"raw_mode_{i:02d}.wav"), mode, fs)
62
 
63
  zip_path = os.path.join(tempfile.gettempdir(), "raw_modes.zip")
64
  with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zf:
65
  for fname in os.listdir(temp_dir):
66
  zf.write(os.path.join(temp_dir, fname), arcname=fname)
67
 
68
  # Also preview the first raw mode (optional)
69
  preview_audio = (fs, raw_modes[0])
70
  return preview_audio, zip_path
71
  gr.Markdown("""
72
  # 🔧 Fast Raw Mode Extractor (GN‑v7, PCA only)
73
  Upload your song → get raw Koopman/PCA modes as WAV files.
74
  **No ICA, no plots – just the raw modes.**
75
  These are the `raw_mode_XX.wav` files from the original GN‑v7.
76
  """)
77
  with gr.Row():
78
  with gr.Column():
79
  audio_in = gr.Audio(type="filepath", label="Your song (any length)")
80
  dim_slider = gr.Slider(16, 64, value=32, step=2, label="Embedding dim (lower = faster)")
81
  tau_slider = gr.Slider(1, 8, value=3, step=1, label="Delay tau")
82
  k_slider = gr.Slider(2, 16, value=8, step=1, label="Number of raw modes (k)")
83
  run_btn = gr.Button("Extract Raw Modes", variant="primary")
84
  with gr.Column():
85
  preview = gr.Audio(label="Preview of first raw mode", type="numpy")
86
  zip_output = gr.File(label="📦 Download all raw modes (ZIP)")
87
 
88
  run_btn.click(
89
  fn=process_to_raw_modes,
90
  inputs=[audio_in, dim_slider, tau_slider, k_slider],
91
  outputs=[preview, zip_output]
92
  )
93
  demo.launch()
 
1
+ #!/usr/bin/env python3
2
  L = (dim - 1) * tau + 1
3
  win = sliding_window_view(x, L)[:, ::tau]
4
  return win[:, ::-1].copy()
5
  """
6
  Returns list of raw PCA mode signals (time domain) of length same as input.
7
  Each mode is a reconstructed time series from one singular vector.
8
  """
9
  # Delay-embed
10
  X = embed(x, dim, tau)
11
  # Normalise rows
12
  a = np.linalg.norm(X, axis=1) + 1e-9
13
  Xv = X / a[:, None]
14
 
15
  # Randomized SVD
16
  U, S, Vt = randomized_svd(Xv, n_components=k, n_iter=5, random_state=0)
17
  W = Vt # shape (k, dim)
18
 
19
  # Project each mode back to original space
20
  Y = Xv @ W.T # activations (T x k)
21
 
22
  raw_modes = []
23
  for i in range(k):
24
  # Reconstruct this mode alone
25
  mode_embedded = Y[:, i:i+1] @ W[i:i+1, :] # (T, dim)
26
  mode_signal = np.real(mode_embedded[:, 0]) * a
27
  raw_modes.append(mode_signal)
28
 
29
  return raw_modes
30
  if file is None:
31
  raise gr.Error("Please upload an audio file.")
32
 
33
  # Load and preprocess
34
  try:
35
  sig, fs = sf.read(file)
36
  except Exception as e:
37
  raise gr.Error(f"Failed to read: {e}")
38
 
39
  if sig.ndim > 1:
40
  sig = np.mean(sig, axis=1)
41
 
42
  # Resample to 16 kHz for speed/consistency
43
  target_sr = 16000
44
  if fs != target_sr:
45
  sig = signal.resample_poly(sig, target_sr, fs)
46
  fs = target_sr
47
 
48
  # Normalise
49
  sig = sig / (np.max(np.abs(sig)) + 1e-9)
50
 
51
  duration = len(sig) / fs
52
  gr.Info(f"Processing {duration:.1f} sec song with dim={dim}, tau={tau}, k={k} ...")
53
 
54
  # Extract raw modes
55
  try:
56
  raw_modes = extract_raw_modes(sig, dim=dim, tau=tau, k=k)
57
  except Exception as e:
58
  raise gr.Error(f"Extraction failed: {e}")
59
 
60
  # Create ZIP with raw mode WAVs
61
  temp_dir = tempfile.mkdtemp()
62
  for i, mode in enumerate(raw_modes):
63
  sf.write(os.path.join(temp_dir, f"raw_mode_{i:02d}.wav"), mode, fs)
64
 
65
  zip_path = os.path.join(tempfile.gettempdir(), "raw_modes.zip")
66
  with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zf:
67
  for fname in os.listdir(temp_dir):
68
  zf.write(os.path.join(temp_dir, fname), arcname=fname)
69
 
70
  # Also preview the first raw mode (optional)
71
  preview_audio = (fs, raw_modes[0])
72
  return preview_audio, zip_path
73
  gr.Markdown("""
74
  # 🔧 Fast Raw Mode Extractor (GN‑v7, PCA only)
75
  Upload your song → get raw Koopman/PCA modes as WAV files.
76
  **No ICA, no plots – just the raw modes.**
77
  These are the `raw_mode_XX.wav` files from the original GN‑v7.
78
  """)
79
  with gr.Row():
80
  with gr.Column():
81
  audio_in = gr.Audio(type="filepath", label="Your song (any length)")
82
  dim_slider = gr.Slider(16, 64, value=32, step=2, label="Embedding dim (lower = faster)")
83
  tau_slider = gr.Slider(1, 8, value=3, step=1, label="Delay tau")
84
  k_slider = gr.Slider(2, 16, value=8, step=1, label="Number of raw modes (k)")
85
  run_btn = gr.Button("Extract Raw Modes", variant="primary")
86
  with gr.Column():
87
  preview = gr.Audio(label="Preview of first raw mode", type="numpy")
88
  zip_output = gr.File(label="📦 Download all raw modes (ZIP)")
89
 
90
  run_btn.click(
91
  fn=process_to_raw_modes,
92
  inputs=[audio_in, dim_slider, tau_slider, k_slider],
93
  outputs=[preview, zip_output]
94
  )
95
  demo.launch()
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ gradio>=3.50.0
2
+ numpy>=1.24.0
3
+ scipy>=1.10.0
4
+ soundfile>=0.12.0
5
+ scikit-learn>=1.3.0