132 lines
3.5 KiB
Python
Executable file
132 lines
3.5 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 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)
|