Skip to content

Instantly share code, notes, and snippets.

@jniimi
Created May 11, 2022 16:08
Show Gist options
  • Save jniimi/938ddd56a8c5332784519f25d614d290 to your computer and use it in GitHub Desktop.
Save jniimi/938ddd56a8c5332784519f25d614d290 to your computer and use it in GitHub Desktop.
import wave
import numpy as np
import pandas as pd
from IPython.display import Audio
class AudioDataFrame:
def __init__(self, bpm = 120, bars = 1, sampling_freq=44100, sub=False, subsub=False):
self.bpm = bpm
self.bars = bars
self.beats = 4 * bars
self.seconds = 60 / bpm * self.beats
self.secfreqperbeat = self.seconds * sampling_freq / self.beats
self.sampling_freq = sampling_freq
self.audio = self.generate_blank_signal()
self.add_metronome(sub=sub, subsub=subsub)
def generate_blank_signal(self):
t = np.arange(self.sampling_freq * self.seconds)
y = t * 0
d = pd.DataFrame({
't':t, 'y':y
})
return d
def add_metronome(self, sub=False, subsub=False):
audio = self.audio
audio['metronome'] = audio['t'] * 0
for i in range(self.beats): # 4th
l = i * self.secfreqperbeat
audio.loc[ audio['t'] == np.round(l), 'metronome'] = 0.5
if sub: # 8th
l8 = l + (self.secfreqperbeat / 2)
audio.loc[ audio['t'] == np.round(l8), 'metronome'] = 0.25
if subsub: # 16th
for j in range(4):
l16 = l + (self.secfreqperbeat / 4) * j
if j == 0:
continue
audio.loc[ self.audio['t'] == np.round(l16), 'metronome'] = 0.25
self.audio = audio
def show(self,parallel=False):
if parallel:
self.audio.drop(columns=['metronome']).plot(x='t', ylim=[-1,1],subplots=True)
else:
self.audio.plot(x='t', y='y', ylim=[-1,1])
def play(self, sounds=None, metronome=True, isLimit=True):
y = self.generate_blank_signal()
if metronome:
self.audio['y'] = self.audio['y'] + self.audio['metronome']
if not sounds:
sounds = self.audio.drop(columns=['t','y','metronome']).columns
print(sounds)
for s in sounds:
self.audio['y'] = self.audio['y'] + self.audio[s]
if isLimit:
self.audio.loc[ self.audio['y'] > 1, 'y' ] = 1
self.audio.loc[ self.audio['y'] < -1, 'y' ] = -1
display(Audio(self.audio['y'], rate=self.sampling_freq))
def load_drumsound(self, sound='CHH'):
drumkit = {
'CRASH': '/content/drive/MyDrive/PyMusic/crash.wav',
'CHH': '/content/drive/MyDrive/PyMusic/hihat.wav',
'KICK': '/content/drive/MyDrive/PyMusic/kick.wav',
'SNARE': '/content/drive/MyDrive/PyMusic/snare.wav',
'CLAP': '/content/drive/MyDrive/PyMusic/clap.wav'
}
f = drumkit[sound]
with wave.open(f, 'rb') as w:
params = w.getparams()
if self.sampling_freq != params[2]:
raise ValueError('Sampling Frequencies between loading sound and the project differ')
w.setpos(0)
s = w.readframes(nframes=params[3])
s = np.frombuffer(s, dtype=np.int16).astype(float)/(2**(8*params[1]-1))
return s, params[3]
def find_position(self, pos):
if pos == 0:
return 0
return np.round((self.sampling_freq * 60 / self.bpm) * pos)
def hit_sound_in_the_specific_point(self, track_name='CHH', sound='CHH', start_beats = [0], volume=1):
if (volume > 1) or (volume < 0):
raise ValueError('Volume must be in 0 - 1.')
audio = self.audio
sound, fr = self.load_drumsound(sound=sound)
for pos in start_beats:
pos = self.find_position(pos)
blank = self.generate_blank_signal().rename(columns={'y':'sound'}).drop(columns='t')
blank.loc[pos:pos+fr-1, 'sound'] = sound * volume
audio = audio.join(blank, how='outer').fillna(0)
if track_name in audio.columns:
audio[track_name] = audio[track_name] + audio['sound']
else:
audio[track_name] = audio['sound']
#audio['y'] = audio['y'] + audio['sound']
audio = audio.drop(columns='sound')
self.audio = audio
audio = AudioDataFrame(bpm = 90, bars = 2, sub=True)
audio.hit_sound_in_the_specific_point(track_name='drm_PERC',sound='CRASH', start_beats=[0], volume=0.1)
audio.hit_sound_in_the_specific_point(track_name='drm_PERC',sound='CHH', start_beats=[0, 0.25, 0.5, 0.75,0.8,0.85,0.9,0.95, 1, 1.25, 1.5, 1.75, 2, 2.125, 2.25, 2.5, 2.75, 3, 3.15, 3.3, 3.45, 3.6], volume=0.2)
audio.hit_sound_in_the_specific_point(track_name='drm_KICK',sound='KICK', start_beats=[0, 0.5, 2.5, 2.75], volume=0.3)
audio.hit_sound_in_the_specific_point(track_name='drm_SNARE',sound='SNARE', start_beats=[1.75, 2.25, 3], volume=0.2)
audio.hit_sound_in_the_specific_point(track_name='drm_PERC',sound='CHH', start_beats=[i/4+4 for i in range(16)], volume=0.2)
audio.hit_sound_in_the_specific_point(track_name='drm_SNARE',sound='SNARE', start_beats=[4, 4.75, 5, 5.5, 6.25, 6.5, 7, 7.5, 7.625, 7.75], volume=0.2)
audio.hit_sound_in_the_specific_point(track_name='drm_CLAP',sound='CLAP', start_beats=[1, 3, 5, 7], volume=0.15)
audio.play(metronome=False)
audio.show(parallel=True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment