-
-
Save usworked/ae406b299705a6deeaba7d2ed7ebfb79 to your computer and use it in GitHub Desktop.
d
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 glob | |
import os, random | |
import sys | |
import math | |
from datetime import datetime | |
from prompt_toolkit.shortcuts import button_dialog | |
#from random import seed | |
import sox | |
from pydub import AudioSegment | |
from pydub.silence import split_on_silence | |
import pydub.scipy_effects | |
#seed() | |
""" | |
start_trim = detect_leading_silence(normalized_sound) | |
end_trim = detect_leading_silence(normalized_sound.reverse()) | |
trimmed_sound = normalized_sound[start_trim:len(normalized_sound)-end_trim] | |
--- COMPRESSIONS --- | |
It sounds like you need to train your ears a bit to know what you are looking for. BPM matching is more about the release than attack, although both parameters interact. | |
The following may help to train your ears: | |
1. take any typical 4 on the floor house loop | |
2. divide 60 by the BPM. | |
For example if the BPM of the loop is 128: | |
1/4 notes are 469ms in duration (kick drums, every other snare) | |
1/8 notes are 234ms in duration (hi hats) | |
1/16 notes are 117ms in duration (closed hats) | |
1/32 notes are 56ms in duration | |
3. Set your attack and release to lowest setting. Then lower your threshold until you see significant gain reduction (-12db is a good starting place). Set a hard knee if the option is present. | |
4. Slowly raise your attack from its lowest value to 60ms. You should hear the transient of the kick start to get louder and louder relative to the rest of the signal, since the first x ms (the value of the attack) of the kick does not get compressed. Now for the BPM related release.. | |
5. Using the ms to note relationships above try setting your release at just under 1/4, just under 1/8 etc. etc. You should start to hear the mix pump as a result of your release setting. This is because the release dictates when the compressor releases the volume back to normal. | |
6. Once you have a an attack and release that fits the 'groove' you want to obtain raise the threshold until your gain reduction is anywhere from -1db to -3db. Then level match your signal using the makeup gain so that your compressed signal is identical in perceived volume to your dry signal. The idea here is to make the compression more transparent so its more felt then heard. | |
Go grab a drink, then come back and A/B the two. Unless you are seeking an obvious effect, the difference should be subtle, but the groove should feel a bit flat when you disable compression. Do this on all sorts of material and you should start to develop an ear for release and attack settings relative to BPM. | |
#compressed_sound = sliced_sound.compress_dynamic_range(-60, 4.0, slice_time-(slice_time*.1), slice_time/1.5) | |
""" | |
def match_target_amplitude(sound, target_dBFS): | |
change_in_dBFS = target_dBFS - sound.max_dBFS | |
return sound.apply_gain(change_in_dBFS) | |
def reverb(sound): | |
sound = sound.fade_out(50) | |
pre_file = os.path.join('src', 'tmp') + '/pre-reverb.wav' | |
post_file = os.path.join('src', 'tmp') + '/post-reverb.wav' | |
if os.path.exists(pre_file): | |
os.remove(pre_file) | |
if os.path.exists(post_file): | |
os.remove(post_file) | |
sound.export(pre_file, format='wav') | |
tfm = sox.Transformer() | |
tfm.reverb(reverberance=75, pre_delay=15, wet_gain=3) | |
tfm.build(pre_file, post_file) | |
new_sound = AudioSegment.from_wav(post_file) | |
return new_sound | |
def pitch(sound, rate): | |
pre_file = os.path.join('src', 'tmp') + '/pre-pitch' + str(rate) + '.wav' | |
post_file = os.path.join('src', 'tmp') + '/post-pitch' + str(rate) + '.wav' | |
if os.path.exists(pre_file): | |
os.remove(pre_file) | |
if os.path.exists(post_file): | |
os.remove(post_file) | |
sound.export(pre_file, format='wav') | |
tfm = sox.Transformer() | |
tfm.pitch(n_semitones=rate) | |
tfm.build(pre_file, post_file) | |
new_sound = AudioSegment.from_wav(post_file) | |
return new_sound | |
def polish(sound, slice_time): | |
duration = len(sound) | |
if duration > slice_time: | |
sliced_sound = sound[:slice_time] | |
else: | |
time_left = min(slice_time - duration, 500) | |
second_of_silence = AudioSegment.silent(time_left) | |
sliced_sound = sound + second_of_silence | |
final_slice_duration = len(sliced_sound) | |
normalized_sound = match_target_amplitude(sliced_sound, -1.0) | |
faded_sound = normalized_sound.fade_out(min(int(final_slice_duration/3), 200)) | |
return faded_sound | |
def build(): | |
incoming_folder = 'incoming' | |
kit_type = button_dialog( | |
title='Type of kit: ', | |
text='Please select the type of kit to make: ', | |
buttons=[ | |
('Drummer', 'drummer') | |
] | |
) | |
if kit_type == 'drummer': | |
folder_kick = os.path.join(os.path.join('src', incoming_folder, 'Drummer', 'kick')) | |
folder_ch = os.path.join(os.path.join('src', incoming_folder, 'Drummer', 'ch')) | |
folder_oh = os.path.join(os.path.join('src', incoming_folder, 'Drummer', 'oh')) | |
folder_snare = os.path.join(os.path.join('src', incoming_folder, 'Drummer', 'snare')) | |
random_kick = os.path.join(folder_kick, random.choice(os.listdir(folder_kick))) | |
print('random_kick: ', random_kick) | |
random_ch = os.path.join(folder_ch, random.choice(os.listdir(folder_ch))) | |
print('random_ch: ', random_ch) | |
random_oh = os.path.join(folder_oh, random.choice(os.listdir(folder_oh))) | |
print('random_oh: ', random_oh) | |
random_snare = os.path.join(folder_snare, random.choice(os.listdir(folder_snare))) | |
print('random_snare: ', random_snare) | |
file_kick = AudioSegment.from_wav(random_kick) | |
file_ch = AudioSegment.from_wav(random_ch) | |
file_oh = AudioSegment.from_wav(random_oh) | |
file_snare = AudioSegment.from_wav(random_snare) | |
playlist = AudioSegment.empty() | |
playlist.set_channels(2) | |
playlist_filename = kit_type + '-' + datetime.now().strftime('%Y-%m-%d-%H-%M-%S') + '.wav' | |
total_time = input('Total time (milliseconds): ') or 4000 | |
total_time = int(total_time) | |
slices = 16 | |
slice_time = math.ceil(total_time/slices) | |
silence = AudioSegment.silent(duration=slice_time) | |
playlist += silence | |
kick = file_kick.set_channels(1) | |
kick = match_target_amplitude(kick, -1.0) | |
ch = file_ch.set_channels(1) | |
ch = match_target_amplitude(ch, -1.0) | |
oh = file_oh.set_channels(1) | |
oh = match_target_amplitude(oh, -1.0) | |
snare = file_snare.set_channels(1) | |
snare = match_target_amplitude(snare, -1.0) | |
kick = split_on_silence(kick, min_silence_len=200, silence_thresh=-40, keep_silence=10) | |
kick = kick[0] | |
ch = split_on_silence(ch, min_silence_len=200, silence_thresh=-40, keep_silence=10) | |
ch = ch[0] | |
oh = split_on_silence(oh, min_silence_len=200, silence_thresh=-40, keep_silence=10) | |
oh = oh[0] | |
snare = split_on_silence(snare, min_silence_len=200, silence_thresh=-40, keep_silence=10) | |
snare = snare[0] | |
kick = kick - 2 | |
ch = ch - 2 | |
oh = oh - 2 | |
snare = snare - 2 | |
kick = kick.low_pass_filter(10000) | |
ch = ch.band_pass_filter(300, 16000) | |
ch = ch.apply_gain_stereo(-1, -5) | |
oh = oh.band_pass_filter(500, 16000) | |
ch = ch.apply_gain_stereo(-5, -1) | |
snare = snare.high_pass_filter(60) | |
snare = snare.apply_gain_stereo(-3, -1) | |
kit = [kick, ch, oh, snare] | |
for sound in kit: | |
polished_sound = polish(sound, slice_time) | |
playlist += polished_sound | |
kick_with_ch = silence.overlay(ch) | |
kick_with_ch = kick_with_ch.overlay(kick, gain_during_overlay=-5) | |
kick_with_ch = polish(kick_with_ch, slice_time) | |
playlist += kick_with_ch | |
ch_reverb = reverb(ch) | |
ch_reverb = polish(ch_reverb, slice_time) | |
playlist += ch_reverb | |
oh_pitchMinus = pitch(oh, -6) | |
oh_pitchMinus = polish(oh_pitchMinus, slice_time) | |
playlist += oh_pitchMinus | |
snare_reverb = reverb(snare) | |
snare_reverb = polish(snare_reverb, slice_time) | |
playlist += snare_reverb | |
kick_with_snare = silence.overlay(kick) | |
kick_with_snare = kick_with_snare.overlay(snare, gain_during_overlay=-5) | |
kick_with_snare = polish(kick_with_snare, slice_time) | |
playlist += kick_with_snare | |
ch_pitchPlus = pitch(ch, +6) | |
kick_with_ch_pitchPlus = silence.overlay(ch_pitchPlus) | |
kick_with_ch_pitchPlus = kick_with_ch_pitchPlus.overlay(kick, gain_during_overlay=-5) | |
kick_with_ch_pitchPlus = polish(kick_with_ch_pitchPlus, slice_time) | |
playlist += kick_with_ch_pitchPlus | |
oh_reverb = reverb(oh) | |
oh_reverb = polish(oh_reverb, slice_time) | |
playlist += oh_reverb | |
snare_with_ch = silence.overlay(ch) | |
snare_with_ch = snare_with_ch.overlay(snare, gain_during_overlay=-5) | |
snare_with_ch = polish(snare_with_ch, slice_time) | |
playlist += snare_with_ch | |
kick_with_oh = silence.overlay(oh) | |
kick_with_oh = kick_with_oh.overlay(kick, gain_during_overlay=-5) | |
kick_with_oh = polish(kick_with_oh, slice_time) | |
playlist += kick_with_oh | |
ch_pitchMinus = pitch(ch, -6) | |
kick_with_ch_pitchMinus = silence.overlay(ch_pitchMinus) | |
kick_with_ch_pitchMinus = kick_with_ch_pitchMinus.overlay(kick, gain_during_overlay=-5) | |
kick_with_ch_pitchMinus = polish(kick_with_ch_pitchMinus, slice_time) | |
playlist += kick_with_ch_pitchMinus | |
oh_reversed = oh.reverse() | |
oh_reversed = polish(oh_reversed, slice_time) | |
playlist += oh_reversed | |
snare_with_oh = silence.overlay(oh) | |
snare_with_oh = snare_with_oh.overlay(snare, gain_during_overlay=-5) | |
snare_with_oh = polish(snare_with_oh, slice_time) | |
playlist += snare_with_oh | |
outgoing_folder = os.path.join('src', 'outgoing', 'Drummer') | |
playlist += silence | |
playlist.export(outgoing_folder + '/' + playlist_filename, format='wav') | |
print(playlist_filename + ' saved.', len(playlist)) | |
''' | |
ordering: | |
1 Kick | |
2 CH | |
3 OH | |
4 Snare | |
5 Kick (with CH) | |
6 CH (slight reverb) | |
7 OH (pitch -1) | |
8 Snare (reverbed) | |
9 Kick (with snare) | |
10 Kick (with CH, pitch +1) | |
11 OH (slight reverb) | |
12 Snare (with CH) | |
13 Kick (with OH) | |
14 Kick (with CH, pitch -1) | |
15 OH (reversed) | |
16 Snare (with OH) | |
default_filename = kit_type + '-' + datetime.date.today().strftime('%Y%b%d') + str(randint(11111, 99999)) + '.wav' | |
playlist_filename = input('Playlist filename: ') or default_filename | |
total_time = input('Total time (milliseconds): ') or 4000 | |
total_time = int(total_time) | |
slices = input('Number of slices: ') or 16 | |
slices = int(slices) | |
slice_time = math.ceil(total_time/slices) | |
preferredWidth = 250 | |
print() | |
print('#slm') | |
print() | |
playlist = AudioSegment.empty() | |
fileList = [] | |
for file in glob.glob(incoming_folder + '/**/*.wav'): | |
folder = os.path.basename(os.path.dirname(file)) | |
if (kit_type == 'drums'): | |
if (folder == 'Kicks') or (folder == 'Snares'): fileList.append(file) | |
if (kit_type == 'percs'): | |
if (folder == 'Hats') or (folder == 'Percs'): fileList.append(file) | |
if (kit_type == 'instruments'): | |
if (folder == 'Instruments'): fileList.append(file) | |
if (len(fileList) != slices): | |
print('There must be ' + str(slices) + ' samples for your chosen kit type. I only see: ', len(fileList)) | |
sys.exit() | |
for file in fileList: | |
folder = os.path.basename(os.path.dirname(file)) | |
filename = os.path.basename(file) | |
preSound = AudioSegment.from_wav(file) | |
sound = eq_process(folder, preSound) | |
duration = len(sound) | |
prefix = folder + '/' + filename + ": " | |
wrapper = textwrap.TextWrapper(initial_indent=prefix, width=preferredWidth) | |
print(wrapper.fill('Initial duration at time of loading: ' + str(duration) + '/' + str(slice_time))) | |
messages = [] | |
if duration > slice_time: | |
sliced_sound = sound[:slice_time] | |
else: | |
time_left = min(slice_time - duration, 500) | |
second_of_silence = AudioSegment.silent(time_left) | |
messages.append('Silence to add: ' + str(len(second_of_silence))) | |
sliced_sound = sound + second_of_silence | |
final_slice_duration = len(sliced_sound) | |
messages.append('With final slice:' + filename + ' : ' + str(final_slice_duration) + '/' + str(slice_time)) | |
faded_sound = sliced_sound.fade_out(min(int(final_slice_duration/3), 200)) | |
normalized_sound = match_target_amplitude(faded_sound, -1.0) | |
playlist += normalized_sound | |
summaryWrapper = textwrap.TextWrapper(initial_indent=' '*len(prefix), width=preferredWidth) | |
for m in messages: | |
print(summaryWrapper.fill(m)) | |
print() | |
playlist.export(outgoing_folder + '/' + playlist_filename + '.wav') | |
print(playlist_filename + '.wav saved.', len(playlist)) | |
''' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment