Fabio Grasso commited on
Commit
d23d710
1 Parent(s): 79d26c1

feat: add plotly, audiorec, update requirements

Browse files
Files changed (4) hide show
  1. README.md +2 -2
  2. app/helpers.py +24 -0
  3. app/main.py +40 -61
  4. requirements.txt +169 -1
README.md CHANGED
@@ -1,10 +1,10 @@
1
  ---
2
- title: Test Space
3
  emoji: 🎶
4
  colorFrom: indigo
5
  colorTo: yellow
6
  sdk: docker
7
- pinned: false
8
  ---
9
 
10
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: Music Splitter
3
  emoji: 🎶
4
  colorFrom: indigo
5
  colorTo: yellow
6
  sdk: docker
7
+ pinned: true
8
  ---
9
 
10
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app/helpers.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydub import AudioSegment
2
+
3
+ import streamlit as st
4
+ import plotly.graph_objs as go
5
+ import plotly.express as px
6
+ import pandas as pd
7
+ import numpy as np
8
+
9
+ @st.cache_data
10
+ def load_audio_segment(path: str, format: str) -> AudioSegment:
11
+ return AudioSegment.from_file(path, format=format)
12
+
13
+ #@st.cache_resource
14
+ def plot_audio(_audio_segment: AudioSegment, title: str = None) -> go.Figure:
15
+ samples = _audio_segment.get_array_of_samples()
16
+ arr = np.array(samples)
17
+ df = pd.DataFrame(arr)
18
+ fig = px.line(df, y=0, render_mode="webgl", line_shape="linear", width=1000, height=60, title=title)
19
+ fig.update_layout(xaxis_fixedrange=True, yaxis_fixedrange=True, yaxis_visible=False, xaxis_visible=False, hovermode=False, margin=dict(l=0, r=0, t=0, b=0))
20
+ #'font': {'size': 18},
21
+ #'xanchor': 'center',
22
+ #'yanchor': 'top'})
23
+ st.plotly_chart(fig, use_container_width=True)
24
+ #return fig
app/main.py CHANGED
@@ -1,18 +1,13 @@
1
  import logging
2
  import os
3
  from pathlib import Path
4
- from shutil import rmtree
5
 
6
- from pydub import AudioSegment
7
  import streamlit as st
8
 
9
- # from lib.st_custom_components import st_audiorec
10
-
11
- try:
12
- from app.demucs_runner import separator
13
- except ImportError:
14
- from demucs_runner import separator
15
-
16
 
17
  logging.basicConfig(
18
  format="%(asctime)s %(levelname)-8s %(message)s",
@@ -34,37 +29,28 @@ int24 = False # output as int24 wavs, unused if 'mp3' is True.
34
  # You cannot set both `float32 = True` and `int24 = True` !!
35
 
36
 
37
- def find_files(in_path):
38
- out = []
39
- for file in Path(in_path).iterdir():
40
- if file.suffix.lower().lstrip(".") in extensions:
41
- out.append(file)
42
- return out
43
-
44
- out_path = Path("tmp")
45
- in_path = Path("tmp")
46
 
47
- # def clean_folders():
48
- # if in_path.exists():
49
- # rmtree(in_path)
50
- # in_path.mkdir()
51
- # if out_path.exists():
52
- # rmtree(out_path)
53
- # out_path.mkdir()
54
 
55
  def url_is_valid(url):
56
- import requests
 
 
 
 
 
57
  try:
58
  r = requests.get(url)
59
  r.raise_for_status()
60
  return True
61
  except Exception:
62
  st.error("URL is not valid.")
 
63
 
64
 
65
  def run():
66
  st.markdown("<h1><center>🎶 Music Source Splitter</center></h1>", unsafe_allow_html=True)
67
-
68
  st.markdown("""
69
  <style>
70
  .st-af {
@@ -80,52 +66,42 @@ def run():
80
  filename = None
81
  choice = st.radio(label=" ", options=["🔗 From URL", "⬆️ Upload File", "🎤 Record Audio"], horizontal=True)
82
  if choice == "🔗 From URL":
83
- url = st.text_input("Paste the URL of the audio file", key="url")
84
  if url != "":
85
  # check if the url is valid
86
  if url_is_valid(url):
87
  with st.spinner("Downloading audio..."):
88
- #clean_folders()
89
  filename = url.split("/")[-1]
90
  os.system(f"wget -O {in_path / filename} {url}")
91
 
92
  elif choice == "⬆️ Upload File":
93
- uploaded_file = st.file_uploader("Choose a file")
94
  if uploaded_file is not None:
95
- #clean_folders()
96
  with open(in_path / uploaded_file.name, "wb") as f:
97
  f.write(uploaded_file.getbuffer())
98
  filename = uploaded_file.name
99
  elif choice == "🎤 Record Audio":
100
- # wav_audio_data = st_audiorec()
101
- # if wav_audio_data is not None:
102
- # if wav_audio_data != b'RIFF,\x00\x00\x00WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00\x80>\x00\x00\x00\xfa\x00\x00\x04\x00\x10\x00data\x00\x00\x00\x00':
103
- # clean_folders()
104
- # filename = "recording.wav"
105
- # with open(in_path / filename, "wb") as f:
106
- # f.write(wav_audio_data)
107
- pass
108
 
109
  if filename is not None:
110
- st.markdown("<hr>", unsafe_allow_html=True)
111
- cols = st.columns(2)
112
- with cols[0]:
113
- st.markdown("<h3>Original Audio</h3>", unsafe_allow_html=True)
114
- with cols[1]:
115
- audio_file = open(in_path / filename, "rb")
116
- audio_bytes = audio_file.read()
117
- _ = st.audio(audio_bytes)
118
 
119
- song = AudioSegment.from_file(in_path / filename, filename.split(".")[-1])
120
  n_secs = round(len(song) / 1000)
121
- start_time = st.slider("Choose the start time", min_value=0, max_value=n_secs, value=0, help=f"Maximum duration is {max_duration} seconds.")
 
 
 
122
  end_time = min(start_time + max_duration, n_secs)
 
123
  tot_time = end_time - start_time
124
  st.info(f"Audio source will be processed from {start_time} to {end_time} seconds.", icon="⏱")
125
-
126
  execute = st.button("Split Music 🎶", type="primary")
127
  if execute:
128
- song = song[start_time*1000:end_time*1000]
129
  song.export(in_path / filename, format=filename.split(".")[-1])
130
  with st.spinner(f"Splitting source audio, it will take almost {round(tot_time*3.6)} seconds..."):
131
  separator(
@@ -144,22 +120,25 @@ def run():
144
  jobs=os.cpu_count(),
145
  verbose=True,
146
  )
147
- pass
148
  last_dir = ".".join(filename.split(".")[:-1])
149
  for file in ["vocals.mp3", "drums.mp3", "bass.mp3", "other.mp3"]:
150
  file = out_path / Path(model) / last_dir / file
151
  st.markdown("<hr>", unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
152
  cols = st.columns(2)
153
  with cols[0]:
154
- label = file.name.split(".")[0].replace("_", " ").capitalize()
155
- # add emoji to label
156
- label = {
157
- "Drums": "🥁",
158
- "Bass": "🎸",
159
- "Other": "🎹",
160
- "Vocals": "🎤",
161
- }.get(label) + " " + label
162
- st.markdown("<h3>" + label + "</h3>", unsafe_allow_html=True)
163
  with cols[1]:
164
  audio_file = open(file, "rb")
165
  audio_bytes = audio_file.read()
 
1
  import logging
2
  import os
3
  from pathlib import Path
 
4
 
5
+ import requests
6
  import streamlit as st
7
 
8
+ from demucs_runner import separator
9
+ from lib.st_custom_components import st_audiorec
10
+ from helpers import load_audio_segment, plot_audio
 
 
 
 
11
 
12
  logging.basicConfig(
13
  format="%(asctime)s %(levelname)-8s %(message)s",
 
29
  # You cannot set both `float32 = True` and `int24 = True` !!
30
 
31
 
32
+ out_path = Path("/tmp")
33
+ in_path = Path("/tmp")
 
 
 
 
 
 
 
34
 
 
 
 
 
 
 
 
35
 
36
  def url_is_valid(url):
37
+ if url.startswith("http") is False:
38
+ st.error("URL should start with http or https.")
39
+ return False
40
+ elif url.split(".")[-1] not in extensions:
41
+ st.error("Extension not supported.")
42
+ return False
43
  try:
44
  r = requests.get(url)
45
  r.raise_for_status()
46
  return True
47
  except Exception:
48
  st.error("URL is not valid.")
49
+ return False
50
 
51
 
52
  def run():
53
  st.markdown("<h1><center>🎶 Music Source Splitter</center></h1>", unsafe_allow_html=True)
 
54
  st.markdown("""
55
  <style>
56
  .st-af {
 
66
  filename = None
67
  choice = st.radio(label=" ", options=["🔗 From URL", "⬆️ Upload File", "🎤 Record Audio"], horizontal=True)
68
  if choice == "🔗 From URL":
69
+ url = st.text_input("Paste the URL of the audio file", key="url", help="Supported formats: mp3, wav, ogg, flac.")
70
  if url != "":
71
  # check if the url is valid
72
  if url_is_valid(url):
73
  with st.spinner("Downloading audio..."):
 
74
  filename = url.split("/")[-1]
75
  os.system(f"wget -O {in_path / filename} {url}")
76
 
77
  elif choice == "⬆️ Upload File":
78
+ uploaded_file = st.file_uploader("Choose a file", type=extensions, key="file", help="Supported formats: mp3, wav, ogg, flac.")
79
  if uploaded_file is not None:
 
80
  with open(in_path / uploaded_file.name, "wb") as f:
81
  f.write(uploaded_file.getbuffer())
82
  filename = uploaded_file.name
83
  elif choice == "🎤 Record Audio":
84
+ wav_audio_data = st_audiorec()
85
+ if wav_audio_data is not None:
86
+ if wav_audio_data != b'RIFF,\x00\x00\x00WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00\x80>\x00\x00\x00\xfa\x00\x00\x04\x00\x10\x00data\x00\x00\x00\x00':
87
+ filename = "recording.wav"
88
+ with open(in_path / filename, "wb") as f:
89
+ f.write(wav_audio_data)
 
 
90
 
91
  if filename is not None:
92
+ song = load_audio_segment(in_path / filename, filename.split(".")[-1])
 
 
 
 
 
 
 
93
 
 
94
  n_secs = round(len(song) / 1000)
95
+ audio_file = open(in_path / filename, "rb")
96
+ audio_bytes = audio_file.read()
97
+ start_time = st.slider("Choose the start time", min_value=0, max_value=n_secs, step=1, value=0, help=f"Maximum duration is {max_duration} seconds.")
98
+ _ = st.audio(audio_bytes, start_time=start_time)
99
  end_time = min(start_time + max_duration, n_secs)
100
+ song = song[start_time*1000:end_time*1000]
101
  tot_time = end_time - start_time
102
  st.info(f"Audio source will be processed from {start_time} to {end_time} seconds.", icon="⏱")
 
103
  execute = st.button("Split Music 🎶", type="primary")
104
  if execute:
 
105
  song.export(in_path / filename, format=filename.split(".")[-1])
106
  with st.spinner(f"Splitting source audio, it will take almost {round(tot_time*3.6)} seconds..."):
107
  separator(
 
120
  jobs=os.cpu_count(),
121
  verbose=True,
122
  )
123
+
124
  last_dir = ".".join(filename.split(".")[:-1])
125
  for file in ["vocals.mp3", "drums.mp3", "bass.mp3", "other.mp3"]:
126
  file = out_path / Path(model) / last_dir / file
127
  st.markdown("<hr>", unsafe_allow_html=True)
128
+ label = file.name.split(".")[0].replace("_", " ").capitalize()
129
+ # add emoji to label
130
+ label = {
131
+ "Drums": "🥁",
132
+ "Bass": "🎸",
133
+ "Other": "🎹",
134
+ "Vocals": "🎤",
135
+ }.get(label) + " " + label
136
+ st.markdown("<center><h3>" + label + "</h3></center>", unsafe_allow_html=True)
137
+
138
  cols = st.columns(2)
139
  with cols[0]:
140
+ auseg = load_audio_segment(file, "mp3")
141
+ plot_audio(auseg)
 
 
 
 
 
 
 
142
  with cols[1]:
143
  audio_file = open(file, "rb")
144
  audio_bytes = audio_file.read()
requirements.txt CHANGED
@@ -1,3 +1,171 @@
1
- streamlit==1.18.1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  demucs==4.0.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  pydub==0.25.1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # This file is autogenerated by pip-compile with Python 3.10
3
+ # by the following command:
4
+ #
5
+ # pip-compile --output-file=requirements.txt --resolver=backtracking requirements.in
6
+ #
7
+ altair==4.2.2
8
+ # via streamlit
9
+ antlr4-python3-runtime==4.9.3
10
+ # via omegaconf
11
+ attrs==22.2.0
12
+ # via jsonschema
13
+ blinker==1.5
14
+ # via streamlit
15
+ cachetools==5.3.0
16
+ # via streamlit
17
+ certifi==2022.12.7
18
+ # via requests
19
+ charset-normalizer==3.0.1
20
+ # via requests
21
+ click==8.1.3
22
+ # via streamlit
23
+ cloudpickle==2.2.1
24
+ # via submitit
25
+ cython==0.29.33
26
+ # via diffq
27
+ decorator==5.1.1
28
+ # via validators
29
  demucs==4.0.0
30
+ # via -r requirements.in
31
+ diffq==0.2.3
32
+ # via demucs
33
+ dora-search==0.1.11
34
+ # via demucs
35
+ einops==0.6.0
36
+ # via demucs
37
+ entrypoints==0.4
38
+ # via altair
39
+ gitdb==4.0.10
40
+ # via gitpython
41
+ gitpython==3.1.31
42
+ # via streamlit
43
+ idna==3.4
44
+ # via requests
45
+ importlib-metadata==6.0.0
46
+ # via streamlit
47
+ jinja2==3.1.2
48
+ # via
49
+ # altair
50
+ # pydeck
51
+ jsonschema==4.17.3
52
+ # via altair
53
+ julius==0.2.7
54
+ # via demucs
55
+ lameenc==1.4.2
56
+ # via demucs
57
+ markdown-it-py==2.2.0
58
+ # via rich
59
+ markupsafe==2.1.2
60
+ # via jinja2
61
+ mdurl==0.1.2
62
+ # via markdown-it-py
63
+ numpy==1.24.2
64
+ # via
65
+ # altair
66
+ # diffq
67
+ # openunmix
68
+ # pandas
69
+ # pyarrow
70
+ # pydeck
71
+ # streamlit
72
+ omegaconf==2.3.0
73
+ # via dora-search
74
+ openunmix==1.2.1
75
+ # via demucs
76
+ packaging==23.0
77
+ # via streamlit
78
+ pandas==1.5.3
79
+ # via
80
+ # -r requirements.in
81
+ # altair
82
+ # streamlit
83
+ pillow==9.4.0
84
+ # via streamlit
85
+ plotly==5.13.0
86
+ # via -r requirements.in
87
+ protobuf==3.20.3
88
+ # via streamlit
89
+ pyarrow==11.0.0
90
+ # via streamlit
91
+ pydeck==0.8.0
92
+ # via streamlit
93
  pydub==0.25.1
94
+ # via -r requirements.in
95
+ pygments==2.14.0
96
+ # via rich
97
+ pympler==1.0.1
98
+ # via streamlit
99
+ pyrsistent==0.19.3
100
+ # via jsonschema
101
+ python-dateutil==2.8.2
102
+ # via
103
+ # pandas
104
+ # streamlit
105
+ pytz==2022.7.1
106
+ # via pandas
107
+ pytz-deprecation-shim==0.1.0.post0
108
+ # via tzlocal
109
+ pyyaml==6.0
110
+ # via
111
+ # demucs
112
+ # omegaconf
113
+ requests==2.28.2
114
+ # via streamlit
115
+ retrying==1.3.4
116
+ # via dora-search
117
+ rich==13.3.1
118
+ # via streamlit
119
+ semver==2.13.0
120
+ # via streamlit
121
+ six==1.16.0
122
+ # via
123
+ # python-dateutil
124
+ # retrying
125
+ smmap==5.0.0
126
+ # via gitdb
127
+ streamlit==1.18.1
128
+ # via -r requirements.in
129
+ submitit==1.4.5
130
+ # via dora-search
131
+ tenacity==8.2.1
132
+ # via plotly
133
+ toml==0.10.2
134
+ # via streamlit
135
+ toolz==0.12.0
136
+ # via altair
137
+ torch==1.13.1
138
+ # via
139
+ # demucs
140
+ # diffq
141
+ # dora-search
142
+ # julius
143
+ # openunmix
144
+ # torchaudio
145
+ torchaudio==0.13.1
146
+ # via
147
+ # demucs
148
+ # openunmix
149
+ tornado==6.2
150
+ # via streamlit
151
+ tqdm==4.64.1
152
+ # via
153
+ # demucs
154
+ # openunmix
155
+ treetable==0.2.5
156
+ # via dora-search
157
+ typing-extensions==4.5.0
158
+ # via
159
+ # streamlit
160
+ # submitit
161
+ # torch
162
+ tzdata==2022.7
163
+ # via pytz-deprecation-shim
164
+ tzlocal==4.2
165
+ # via streamlit
166
+ urllib3==1.26.14
167
+ # via requests
168
+ validators==0.20.0
169
+ # via streamlit
170
+ zipp==3.14.0
171
+ # via importlib-metadata