render gongs
This commit is contained in:
parent
2fca6615c2
commit
a0650e6475
6 changed files with 180 additions and 3 deletions
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -1,2 +1,10 @@
|
||||||
*.swp
|
*.swp
|
||||||
*.pyc
|
*.pyc
|
||||||
|
gongs_wav
|
||||||
|
CLIPS.json
|
||||||
|
DRONES.json
|
||||||
|
GONGS.json
|
||||||
|
MUSIC.json
|
||||||
|
PATHS.json
|
||||||
|
VOCALS.json
|
||||||
|
|
||||||
|
|
12
gongs_wav.py
Executable file
12
gongs_wav.py
Executable file
|
@ -0,0 +1,12 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
from glob import glob
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
|
||||||
|
for f in glob('gongs/*/*.mp3'):
|
||||||
|
t = f.replace('gongs/', 'gongs_wav/').replace('.mp3', '.wav')
|
||||||
|
print(f, t)
|
||||||
|
folder = os.path.dirname(t)
|
||||||
|
if not os.path.exists(folder):
|
||||||
|
os.makedirs(folder)
|
||||||
|
subprocess.call(['ffmpeg', '-i', f, t])
|
2
pi.py
2
pi.py
|
@ -6,6 +6,7 @@ class random(object):
|
||||||
PI = str(mp.pi).replace('.', '')
|
PI = str(mp.pi).replace('.', '')
|
||||||
|
|
||||||
def __init__(self, offset=0):
|
def __init__(self, offset=0):
|
||||||
|
self.position = offset
|
||||||
self.numbers = list(map(int, self.PI[offset:]))
|
self.numbers = list(map(int, self.PI[offset:]))
|
||||||
|
|
||||||
def __call__(self):
|
def __call__(self):
|
||||||
|
@ -14,5 +15,6 @@ class random(object):
|
||||||
mp.dps += 1000
|
mp.dps += 1000
|
||||||
self.PI = str(mp.pi).replace('.', '')
|
self.PI = str(mp.pi).replace('.', '')
|
||||||
self.numbers = list(map(int, self.PI[offset:]))
|
self.numbers = list(map(int, self.PI[offset:]))
|
||||||
|
self.position += 1
|
||||||
return self.numbers.pop(0)
|
return self.numbers.pop(0)
|
||||||
|
|
||||||
|
|
|
@ -419,6 +419,10 @@ def sequence(seq, letter):
|
||||||
tduration = sum([c['duration'] for c in result[track]])
|
tduration = sum([c['duration'] for c in result[track]])
|
||||||
if not abs(tduration - duration) < 0.000001:
|
if not abs(tduration - duration) < 0.000001:
|
||||||
raise Exception('invalid duration on track: %s %s vs %s %s' % (track, tduration, duration, result[track]))
|
raise Exception('invalid duration on track: %s %s vs %s %s' % (track, tduration, duration, result[track]))
|
||||||
|
result['gongs'] = {
|
||||||
|
'tracks': 100 + seq() * 23,
|
||||||
|
'offset': seq.position,
|
||||||
|
}
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
132
render_gongs.py
Executable file
132
render_gongs.py
Executable file
|
@ -0,0 +1,132 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
from collections import defaultdict
|
||||||
|
import string
|
||||||
|
from glob import glob
|
||||||
|
|
||||||
|
import nmt
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from pi import random
|
||||||
|
from keywords import KEYWORDS
|
||||||
|
import ox
|
||||||
|
import ox.web.auth
|
||||||
|
|
||||||
|
|
||||||
|
if not os.path.exists('GONGS.json'):
|
||||||
|
GONGS = defaultdict(list)
|
||||||
|
prefix = 'gongs_wav'
|
||||||
|
wavs = glob('%s/*/*.wav' % prefix)
|
||||||
|
for path in sorted(wavs):
|
||||||
|
name = os.path.basename(path).split('.')[0]
|
||||||
|
GONGS[name] = {
|
||||||
|
'path': path,
|
||||||
|
'duration': ox.avinfo(path)['duration']
|
||||||
|
}
|
||||||
|
with open('GONGS.json', 'w') as fd:
|
||||||
|
json.dump(GONGS, fd, indent=2, sort_keys=True)
|
||||||
|
else:
|
||||||
|
GONGS = json.load(open('GONGS.json'))
|
||||||
|
|
||||||
|
|
||||||
|
def random_choice(seq, items):
|
||||||
|
n = n_ = len(items) - 1
|
||||||
|
#print('len', n)
|
||||||
|
if n == 0:
|
||||||
|
return items[0]
|
||||||
|
r = seq()
|
||||||
|
base = 10
|
||||||
|
while n > 10:
|
||||||
|
n /= 10
|
||||||
|
#print(r)
|
||||||
|
r += seq()
|
||||||
|
base += 10
|
||||||
|
r = int(n_ * r / base)
|
||||||
|
#print('result', r, items)
|
||||||
|
return items[r]
|
||||||
|
|
||||||
|
|
||||||
|
def splitint(number, by):
|
||||||
|
div = int(number/by)
|
||||||
|
mod = number % by
|
||||||
|
return [div + 1 if i > (by - 1 - mod) else div for i in range(by)]
|
||||||
|
|
||||||
|
|
||||||
|
def add_blank(track, d):
|
||||||
|
if track and track[-1].get('blank'):
|
||||||
|
track[-1]['duration'] += d
|
||||||
|
else:
|
||||||
|
blank = {'blank': True, 'duration': d}
|
||||||
|
track.append(blank)
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def get_gongs(seq, result, duration, tracks=42):
|
||||||
|
for tn in range(tracks):
|
||||||
|
track = 'gongs%d' % tn
|
||||||
|
if track not in result:
|
||||||
|
result[track] = []
|
||||||
|
|
||||||
|
position = 0
|
||||||
|
while position < duration:
|
||||||
|
n1 = seq()
|
||||||
|
n2 = seq()
|
||||||
|
clip = GONGS['%d_%d' % (n1, n2)]
|
||||||
|
if position + clip['duration'] < duration:
|
||||||
|
position += clip['duration']
|
||||||
|
result[track].append(clip)
|
||||||
|
else:
|
||||||
|
c = clip.copy()
|
||||||
|
c['duration'] = duration - position
|
||||||
|
result[track].append(c)
|
||||||
|
position += c['duration']
|
||||||
|
if position < duration:
|
||||||
|
position += add_blank(result[track], duration - position)
|
||||||
|
|
||||||
|
for track in result:
|
||||||
|
if result[track]:
|
||||||
|
tduration = sum([c['duration'] for c in result[track]])
|
||||||
|
if not abs(tduration - duration) < 0.000001:
|
||||||
|
raise Exception('invalid duration on track: %s %s vs %s %s' % (track, tduration, duration, result[track]))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def mix_gongs(data, output):
|
||||||
|
mixed = None
|
||||||
|
for n, clips in enumerate(data.values()):
|
||||||
|
track = [nmt.sound2np(c['path']) for c in clips]
|
||||||
|
track = np.vstack(track)
|
||||||
|
if mixed is None:
|
||||||
|
mixed = track.astype(np.int)
|
||||||
|
else:
|
||||||
|
limit = min(len(track), len(mixed))
|
||||||
|
mixed = mixed[:limit]
|
||||||
|
track = track[:limit]
|
||||||
|
mixed += track.astype(np.int)
|
||||||
|
print(n)
|
||||||
|
|
||||||
|
d = np.sqrt(len(data))
|
||||||
|
while \
|
||||||
|
np.max((mixed/d).astype(np.int)) != np.max((mixed/d).astype(np.int16)) \
|
||||||
|
or np.min((mixed/d).astype(np.int)) != np.min((mixed/d).astype(np.int16)):
|
||||||
|
d = d + 2
|
||||||
|
mixed = (mixed/d).astype(np.int16)
|
||||||
|
nmt.np2sound(mixed, output)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
n = int(sys.argv[1])
|
||||||
|
seq = random(n)
|
||||||
|
duration = float(sys.argv[2]) + 10
|
||||||
|
tracks = int(sys.argv[3])
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
tracks = int(sys.argv[1])
|
||||||
|
else:
|
||||||
|
tracks = 42
|
||||||
|
data = get_gongs(seq, {}, duration, tracks)
|
||||||
|
mix_gongs(data, output)
|
||||||
|
with open(output + '.json', 'w') as fd:
|
||||||
|
json.dump(result, fd, indent=4, sort_keys=True)
|
|
@ -50,8 +50,7 @@ def add_clip(playlist, clip, in_, duration):
|
||||||
tractor.plant_filter(volume)
|
tractor.plant_filter(volume)
|
||||||
playlist.append(tractor)
|
playlist.append(tractor)
|
||||||
|
|
||||||
def add_audio_clip(playlist, file_, duration):
|
def add_audio_clip(playlist, file_, duration, in_=0):
|
||||||
in_ = 0
|
|
||||||
if not isinstance(file_, str):
|
if not isinstance(file_, str):
|
||||||
file_ = file_.encode('utf-8')
|
file_ = file_.encode('utf-8')
|
||||||
clip = mlt.Producer(profile, file_)
|
clip = mlt.Producer(profile, file_)
|
||||||
|
@ -109,6 +108,7 @@ target_vocals = source.replace('.json', '.vocals.xml')
|
||||||
target_music = source.replace('.json', '.music.xml')
|
target_music = source.replace('.json', '.music.xml')
|
||||||
target_drones = source.replace('.json', '.drones.xml')
|
target_drones = source.replace('.json', '.drones.xml')
|
||||||
target_source = source.replace('.json', '.source.xml')
|
target_source = source.replace('.json', '.source.xml')
|
||||||
|
gongs_wav = source.replace('.json', '.gongs.wav')
|
||||||
|
|
||||||
with open(source) as fd:
|
with open(source) as fd:
|
||||||
data = json.load(fd)
|
data = json.load(fd)
|
||||||
|
@ -119,12 +119,14 @@ music = mlt.Playlist()
|
||||||
vocals = mlt.Playlist()
|
vocals = mlt.Playlist()
|
||||||
drones0 = mlt.Playlist()
|
drones0 = mlt.Playlist()
|
||||||
drones1 = mlt.Playlist()
|
drones1 = mlt.Playlist()
|
||||||
|
gongs = mlt.Playlist()
|
||||||
|
|
||||||
# hide Set to 1 to hide the video (make it an audio-only track),
|
# hide Set to 1 to hide the video (make it an audio-only track),
|
||||||
# 2 to hide the audio (make it a video-only track),
|
# 2 to hide the audio (make it a video-only track),
|
||||||
# or 3 to hide audio and video (hidden track).
|
# or 3 to hide audio and video (hidden track).
|
||||||
drones0.set("hide", 1)
|
drones0.set("hide", 1)
|
||||||
drones1.set("hide", 1)
|
drones1.set("hide", 1)
|
||||||
|
gongs.set("hide", 1)
|
||||||
vocals.set("hide", 1)
|
vocals.set("hide", 1)
|
||||||
music.set("hide", 1)
|
music.set("hide", 1)
|
||||||
|
|
||||||
|
@ -194,8 +196,25 @@ save_xml(drones, target_drones)
|
||||||
|
|
||||||
save_xml(music, target_music)
|
save_xml(music, target_music)
|
||||||
|
|
||||||
|
# render gongs
|
||||||
|
subprocess.call([
|
||||||
|
# offset in pi, duration, number of tracks, target
|
||||||
|
'./render_gongs.py',
|
||||||
|
str(data['gongs']['offset']),
|
||||||
|
str(duration),
|
||||||
|
str(data['gongs']['tracks']),
|
||||||
|
gongs_wav
|
||||||
|
])
|
||||||
|
# load gongs
|
||||||
|
add_audio_clip(gongs, gongs_wav, int(duration * fps), int(5*fps))
|
||||||
|
|
||||||
|
|
||||||
# mix drones + music
|
# mix drones + music
|
||||||
mtractor = mix_audio_tracks(drones, music, 0.3)
|
#mtractor = mix_audio_tracks(drones, music, 0.3)
|
||||||
|
|
||||||
|
# mix gongs + music
|
||||||
|
mtractor = mix_audio_tracks(gongs, music, 0.3)
|
||||||
|
|
||||||
norm = mlt.Filter(profile, "volume")
|
norm = mlt.Filter(profile, "volume")
|
||||||
# lower volume
|
# lower volume
|
||||||
norm.set("gain", "-12dB")
|
norm.set("gain", "-12dB")
|
||||||
|
|
Loading…
Reference in a new issue