experimentations/random_audio_slices.py

92 lines
3.0 KiB
Python

#!/usr/bin/env python3
# Copyright (C) 2021 harrysentonbury
# GNU General Public License v3.0
from audio2numpy import open_audio
import numpy as np
import scipy.io.wavfile as wf
import sounddevice as sd
class ThyRandomAudioSlices():
"""
Slices and randomly rearange audio arrays.
data - numpy array.
window_size - int, optional size of slice in samples. default=2**14
flip - boolean, optional reverse output. default=False.
fade_length - int, optional fade in and fade out length of slices in samples
default=300
"""
def __init__(self, data, window_size=2**14, flip=False, fade_length=500):
self.data = data
self.window_size = window_size
self.flip = flip
self.fade_length = fade_length
def chop_and_chuck(self):
self.fade_size = self.fade_length if self.fade_length < \
self.window_size else self.window_size
self.extra_size = np.size(self.data) % self.window_size
self.extra = np.zeros(self. window_size - self.extra_size)
self.data = np.concatenate((self.data, self.extra))
self.range_size = np.size(self.data) // self.window_size
self.fade_in = np.linspace(0, 1, self.fade_size)
self.fade_out = np.flip(self.fade_in)
self.bitties = np.zeros((self.range_size, self.window_size + self.fade_size))
self.result = np.zeros_like(self.data)
for i in range(self.range_size):
if i == 0:
self.bitties[i, :] = self.data[:self.window_size + self.fade_size]
else:
self.bitties[i, :] = self.data[(i*self.window_size) - \
self.fade_size:(i*self.window_size)+self.window_size]
# shuffle
rng = np.random.default_rng()
rng.shuffle(self.bitties)
self.bitties[1:, :self.fade_size] *= self.fade_in
self.bitties[1:, -self.fade_size:] *= self.fade_out
for i in range(self.range_size):
if i == 0:
self.result[:self.window_size + self.fade_size] += self.bitties[i, :]
else:
self.result[(i * self.window_size) - \
self.fade_size:(i * self.window_size) + \
self.window_size] += self.bitties[i, :]
return self.result
path_to_file = "audio/brown_8.mp3"
# read mp3 or wav with appropriate package.
if path_to_file.endswith(".mp3"):
sound, sample_rate = open_audio(path_to_file)
else:
sample_rate, sound = wf.read(path_to_file)
# if stereo convert to mono else carry on.
try:
sound = sound[:, 0] + sound[:, 1]
except IndexError:
pass
# convert to float64 then normalize.
sound = np.float64(sound)
sound = sound / np.max(np.abs(sound))
# repeat the infile a few times just to make this example longer.
sound = np.concatenate((sound, sound, sound))
window_size = 2**12
shuffle_object = ThyRandomAudioSlices(sound, window_size, fade_length=1500)
shuffle_object.flip = True
result = shuffle_object.chop_and_chuck()
# play
sd.play(result, sample_rate)
sd.wait()