Skip to content

Instantly share code, notes, and snippets.

@jamak
Forked from JayMcYaru/spectralRotation.py
Created May 19, 2024 00:03
Show Gist options
  • Save jamak/bee63df486462f669e3ba98bb6acba60 to your computer and use it in GitHub Desktop.
Save jamak/bee63df486462f669e3ba98bb6acba60 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment