pandora_cdosea/render_gongs.py

133 lines
3.6 KiB
Python
Executable File

#!/usr/bin/python3
import os
import sys
import json
import subprocess
from collections import defaultdict
import string
from glob import glob
import time
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])
output = sys.argv[4]
t0 = time.time()
data = get_gongs(seq, {}, duration, tracks)
mix_gongs(data, output)
with open(output + '.json', 'w') as fd:
json.dump(data, fd, indent=4, sort_keys=True)
print('render_gongs of %s took %s' % (output, time.time()-t0))