-
-
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~)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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