Spaces:
Build error
Build error
Download pages/sonification_utils.py from ulas742/spatial-audio-study: direct link, hf CLI and curl.
- Browser
- Download file 4.86 kB
-
https://huggingface.co/spaces/ulas742/spatial-audio-study/resolve/main/pages/sonification_utils.py
- Command line
-
hf download hf://spaces/ulas742/spatial-audio-study/pages/sonification_utils.py
-
curl -L -o sonification_utils.py https://huggingface.co/spaces/ulas742/spatial-audio-study/resolve/main/pages/sonification_utils.py
4.86 kB
| import base64 | |
| from io import BytesIO | |
| import matplotlib.pyplot as plt | |
| from pages.common import AUDIO_PATH | |
| from scipy.io import wavfile | |
| from toph.audio.effect import SimplePanner | |
| from toph.audio.playable import Chain, Silence, SineWave, Wave | |
| from toph.audio.spatial import SpatialPanner | |
| from toph.audio.stage import AudioStage | |
| from toph.axis.spatial import LinearSpatialAxis | |
| def ax_gen(domain, range_): | |
| do_scale = max(domain) - min(domain) | |
| ra_scale = max(range_) - min(range_) | |
| def foo(dp): | |
| dx = dp - min(domain) | |
| sdx = dx / do_scale | |
| return min(range_) + sdx * ra_scale | |
| return foo | |
| def sonify_y_ax(xs, ys, mode, gaps=0.5): | |
| """ """ | |
| with AudioStage() as stage: | |
| space_ax = LinearSpatialAxis( | |
| domain=((min(xs), max(xs)), (min(ys), max(ys))), | |
| range_=((-50.0, 50.0), (-45.0, 90.0)), | |
| ) | |
| # TODO: replace with linear axis when implemented | |
| lin_ax = ax_gen(domain=(min(ys), max(ys)), range_=(110, 880)) | |
| simple_lr_ax = ax_gen(domain=(min(xs), max(xs)), range_=(-0.98, +0.99)) | |
| marks = [] | |
| for x, y in zip(xs, ys): | |
| if mode == "full_spatial": | |
| r, az, el = space_ax((x, y)) | |
| marks.extend( | |
| [ | |
| Wave(AUDIO_PATH).add_effect(SpatialPanner(az, el, r * 2)), | |
| Silence(secs=gaps), | |
| ] | |
| ) | |
| elif mode == "pitch": | |
| # keep the y as 0 to get a good r | |
| az = simple_lr_ax(x) | |
| freq = lin_ax(y) | |
| print(az, freq) | |
| marks.extend( | |
| [ | |
| SineWave(vol=0.15, f=freq, secs=0.5).add_effect( | |
| SimplePanner(dir=az) | |
| ), | |
| Silence(secs=gaps), | |
| ] | |
| ) | |
| elif mode == "both": | |
| # keep the y as 0 to get a good r | |
| r, az, el = space_ax((x, y)) | |
| freq = lin_ax(y) | |
| marks.extend( | |
| [ | |
| SineWave(vol=0.15, f=freq, secs=0.5).add_effect( | |
| SpatialPanner(az, el, r) | |
| ), | |
| Silence(secs=gaps), | |
| ] | |
| ) | |
| return stage.get_ndarray(Chain(*marks)) | |
| def sonify_x_ax(xs, ys, x_mode, y_mode, gaps=0.5): | |
| """ """ | |
| with AudioStage(frame_rate=48000) as stage: | |
| # TODO: replace with linear axis when implemented | |
| lin_ax = ax_gen(domain=(min(xs), max(xs)), range_=(-1.0, +1.0)) | |
| pitch_ax = ax_gen(domain=(min(ys), max(ys)), range_=(110, 880)) | |
| x_deltas = [xs[idx + 1] - xs[idx] for idx in range(len(xs) - 1)] | |
| x_deltas.append(0.0) | |
| gap_ax = ax_gen(domain=(min(x_deltas), max(x_deltas)), range_=(0.25, 1.25)) | |
| marks = [] | |
| for idx, (x, y) in enumerate(zip(xs, ys)): | |
| audio_src = ( | |
| SineWave(vol=0.15, f=440, secs=0.5) | |
| if y_mode == "static" | |
| else SineWave(vol=0.15, f=pitch_ax(y), secs=0.5) | |
| ) | |
| if x_mode == "spatial": | |
| marks.extend( | |
| [ | |
| audio_src.add_effect(SimplePanner(dir=lin_ax(x))), | |
| Silence(secs=gaps), | |
| ] | |
| ) | |
| elif x_mode == "gaps": | |
| marks.append(audio_src) | |
| if x_deltas[idx] > 0.0: | |
| marks.append(Silence(secs=gap_ax(x_deltas[idx]))) | |
| return stage.get_ndarray(Chain(*marks)) | |
| def get_audio_comp(arr, frame_rate, visible=True, autoplay=False) -> str: | |
| """Takes an audio array | |
| returns an audio component | |
| """ | |
| v_file = BytesIO() | |
| wavfile.write( | |
| v_file, | |
| rate=frame_rate, | |
| # todo: handle formats other than int16, make it better | |
| data=arr, | |
| ) | |
| v_file.seek(0) | |
| b64 = base64.b64encode(v_file.read()).decode() | |
| md = f"""<audio {"style='display: none'" if not visible else ''} controls {'autoplay="true"' if autoplay else ''}> | |
| """ | |
| src = f"""<source src="data:audio/wav;base64,{b64}" type="audio/wav">""" | |
| return md + src + "</audio>" | |
| SONIFICATION_FUNCTIONS = {"sonify_y_ax": sonify_y_ax, "sonify_x_ax": sonify_x_ax} | |
| def plot_four(datasets, idxs, xlim=None, ylim=None, s=75): | |
| fig, axes = plt.subplots(2, 2, figsize=(8, 8)) | |
| for i, ax in enumerate(axes.flat): | |
| ax.scatter(datasets[idxs[i]]["x"], datasets[idxs[i]]["y"], s=100) | |
| ax.set_title(f"Option {i + 1}") | |
| ax.grid(True) | |
| if xlim: | |
| ax.set_xlim(xlim) | |
| if ylim: | |
| ax.set_ylim(ylim) | |
| ax.set_xticks([]) | |
| ax.set_yticks([]) | |
| plt.tight_layout() | |
| return fig | |