Skip to content

Instantly share code, notes, and snippets.

@JayMcYaru
Forked from ravarcheon/spectralRotation.py
Last active May 19, 2024 00:03
Show Gist options
  • Select an option

  • Save JayMcYaru/c08537de7d23d2095fef216bfd0c4153 to your computer and use it in GitHub Desktop.

Select an option

Save JayMcYaru/c08537de7d23d2095fef216bfd0c4153 to your computer and use it in GitHub Desktop.
rotates an audio file by 90 degrees in the spectrum while being a reversible process with minimal loss (only floating point errors which are like -150 dB but thats literally silence ahaha~)
import numpy as np
import soundfile as sf
from scipy.fftpack import fft, ifft
from tkinter import filedialog
import tkinter as tk
import os
def open_file_dialog():
root = tk.Tk()
root.withdraw()
file_path = filedialog.askopenfilename(title="Select an audio File", filetypes=[("MP3 Files", "*.mp3"),("WAV Files","*.wav")])
if file_path:
return file_path
else:
print("No file selected. Exiting.")
exit()
# File save dialog logic
def save_dialog():
root = tk.Tk()
root.withdraw()
save_path = filedialog.askdirectory()
if save_path:
return save_path
else:
print("No save location selected. Exiting.")
exit()
def rotateSignal(signal,flip):
if flip:
signal = signal[::-1]
x = np.concatenate((signal, signal[1:][::-1])) # concatenating the array with a reverse of itself makes it such that the fourier transform doesn't layer over a reversed version of itself in the inverse fft
rotSig = np.real(ifft(x))
# delete the second half of the array cus fft does that thing where it also has a reversed spectrum after the regular one
rotSig = rotSig[:len(rotSig) // 2 + 1] #cheeky little plus 1 here
# this thing is quite important cus the output is usually really quiet, so this conserves the energy that the input has
energyRatio = np.sqrt(np.sum(np.abs(signal)**2) / np.sum(np.abs(rotSig)**2))
rotSig *= energyRatio
return rotSig
def specRotate(input, output,flip=True):
signal, sampleRate = sf.read(input, dtype='float64')
if signal.ndim == 1: # mono
rotSig = rotateSignal(signal,flip)
else: # stereo
rotSig = np.column_stack((rotateSignal(signal[:, 0],flip), rotateSignal(signal[:, 1],flip)))
sf.write(output, rotSig.astype(np.float64), sampleRate, format='WAV', subtype='FLOAT')
print(f"saved {output}")
# this is a 32 bit float wav, meaning that clipping isn't an issue, but DO keep in mind that you probably will get a file that has amplitudes over 0dB
if __name__ == "__main__":
inputFile = open_file_dialog()
output = save_dialog()
rotated = os.path.join(output,'rotated.wav')
swapped = os.path.join(output,'swapped.wav')
inverted = os.path.join(output,'inverted.wav')
specRotate(inputFile, rotated) # this is a 90 degree clockwise rotation where the beginning will be at nyquist frequency and the end be at 0hz
specRotate(inputFile, swapped,False) # this is a swap of the time and frequency axiis, this time the end of the sound is at nyquist and the beginning is at 0hz
specRotate(swapped, inverted) # this is a vertical flip of the input signal and reversed
# a 180 degree rotation can be achieved simply by reversing inverted.wav
# a 270 degree rotation can be achieved simply by reversing swapped.wav
#skibidi('swapped.wav', 'restored.wav',False) # for comparing loss in reconstruction if you want, delete this line if you dont care about that lol
#i make music too so please check that out lolol https://ravarcheon.fanlink.tv/profiles https://linktr.ee/ravarcheon https://www.youtube.com/ravarcheon
@JayMcYaru

Copy link
Copy Markdown
Author

Added code to allow browsing for the specific mp3/wav files and selecting outut folder

@Tjerbor

Tjerbor commented May 18, 2024

Copy link
Copy Markdown

Jpgregoriogodoy my beloved

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment