audio downmix
This commit is contained in:
parent
135861e9d7
commit
e713d724b2
4 changed files with 136 additions and 20 deletions
|
@ -4,7 +4,7 @@ import os
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
for xml in glob('output/*/*.xml'):
|
for xml in sorted(glob('output/*/*.xml')):
|
||||||
if xml.endswith('.audio.xml'):
|
if xml.endswith('.audio.xml'):
|
||||||
continue
|
continue
|
||||||
audio_xml = xml.replace('.xml', '.audio.xml')
|
audio_xml = xml.replace('.xml', '.audio.xml')
|
||||||
|
@ -16,6 +16,7 @@ for xml in glob('output/*/*.xml'):
|
||||||
subprocess.call([
|
subprocess.call([
|
||||||
'qmelt', xml, '-consumer', 'avformat:' + video, 'vcodec=libx264', 'strict=-2'
|
'qmelt', xml, '-consumer', 'avformat:' + video, 'vcodec=libx264', 'strict=-2'
|
||||||
])
|
])
|
||||||
|
'''
|
||||||
subprocess.call([
|
subprocess.call([
|
||||||
'qmelt', audio_xml, '-consumer', 'avformat:' + audio,
|
'qmelt', audio_xml, '-consumer', 'avformat:' + audio,
|
||||||
])
|
])
|
||||||
|
@ -33,3 +34,5 @@ for xml in glob('output/*/*.xml'):
|
||||||
os.unlink(video)
|
os.unlink(video)
|
||||||
os.unlink(audio)
|
os.unlink(audio)
|
||||||
shutil.move(pre, mp4)
|
shutil.move(pre, mp4)
|
||||||
|
'''
|
||||||
|
shutil.move(video, mp4)
|
||||||
|
|
73
render.py
73
render.py
|
@ -241,29 +241,68 @@ def sequence(seq, letter):
|
||||||
blank = {'blank': True, 'duration': duration - last_text}
|
blank = {'blank': True, 'duration': duration - last_text}
|
||||||
result['text'].append(blank)
|
result['text'].append(blank)
|
||||||
|
|
||||||
|
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
|
||||||
|
position += d
|
||||||
|
|
||||||
# music
|
# music
|
||||||
|
track = 'music'
|
||||||
if letter in MUSIC:
|
if letter in MUSIC:
|
||||||
position = last_music = 0
|
position = 0
|
||||||
while position < duration:
|
while position < duration:
|
||||||
n = seq()
|
n = seq()
|
||||||
if n == 0:
|
if n < 5:
|
||||||
blank = {'blank': True, 'duration': position - last_music}
|
n = seq()
|
||||||
result['music'].append(blank)
|
position += add_blank(result[track], min(n, duration-position))
|
||||||
|
else:
|
||||||
n = seq()
|
n = seq()
|
||||||
|
|
||||||
clip = MUSIC[letter][n]
|
clip = MUSIC[letter][n]
|
||||||
position += clip['duration']
|
position += clip['duration']
|
||||||
if position > duration and result['music'][-1].get('blank'):
|
if position > duration \
|
||||||
result['music'][-1]['duration'] -= (position-duration)
|
and result[track][-1].get('blank') \
|
||||||
|
and result[track][-1]['duration'] > clip['duration']:
|
||||||
|
result[track][-1]['duration'] -= (position-duration)
|
||||||
|
print('one last alignment')
|
||||||
position = duration
|
position = duration
|
||||||
result['music'].append(clip)
|
if position <= duration:
|
||||||
last_music = position
|
result[track].append(clip)
|
||||||
else:
|
else:
|
||||||
position += n
|
position -= clip['duration']
|
||||||
if last_music < duration:
|
break
|
||||||
blank = {'blank': True, 'duration': duration - last_music}
|
if position < duration:
|
||||||
result['music'].append(blank)
|
position += add_blank(result[track], duration - position)
|
||||||
# vocals
|
# vocals
|
||||||
|
track = 'vocals'
|
||||||
|
if letter in VOCALS:
|
||||||
|
position = 0
|
||||||
|
while position < duration:
|
||||||
|
n = seq()
|
||||||
|
if n < 5:
|
||||||
|
n = seq()
|
||||||
|
position += add_blank(result[track], min(n, duration-position))
|
||||||
|
else:
|
||||||
|
n = seq()
|
||||||
|
clip = VOCALS[letter][n]
|
||||||
|
position += clip['duration']
|
||||||
|
if position > duration \
|
||||||
|
and result[track][-1].get('blank') \
|
||||||
|
and result[track][-1]['duration'] > clip['duration']:
|
||||||
|
result[track][-1]['duration'] -= (position-duration)
|
||||||
|
position = duration
|
||||||
|
if position <= duration:
|
||||||
|
result[track].append(clip)
|
||||||
|
else:
|
||||||
|
position -= clip['duration']
|
||||||
|
break
|
||||||
|
if position < duration:
|
||||||
|
print('padding', track, duration, position)
|
||||||
|
position += add_blank(result[track], duration - position)
|
||||||
|
'''
|
||||||
if letter in VOCALS:
|
if letter in VOCALS:
|
||||||
n = seq()
|
n = seq()
|
||||||
clip = VOCALS[letter][n]
|
clip = VOCALS[letter][n]
|
||||||
|
@ -279,7 +318,13 @@ def sequence(seq, letter):
|
||||||
if n != 1:
|
if n != 1:
|
||||||
blank = {'blank': True, 'duration': silence - silence_start}
|
blank = {'blank': True, 'duration': silence - silence_start}
|
||||||
result['vocals'].append(blank)
|
result['vocals'].append(blank)
|
||||||
|
'''
|
||||||
|
|
||||||
|
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 %s vs %s %s' % (tduration, duration, result[track]))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@ -305,4 +350,4 @@ if __name__ == '__main__':
|
||||||
with open(tjson, 'w') as fd:
|
with open(tjson, 'w') as fd:
|
||||||
fd.write(current)
|
fd.write(current)
|
||||||
subprocess.call(['./render_mlt.py', tjson])
|
subprocess.call(['./render_mlt.py', tjson])
|
||||||
subprocess.call(['./render_audio.py', tjson])
|
#subprocess.call(['./render_audio.py', tjson])
|
||||||
|
|
|
@ -43,7 +43,6 @@ def add_clip(playlist, file_, duration):
|
||||||
def add_blank(playlist, length):
|
def add_blank(playlist, length):
|
||||||
playlist.blank(length)
|
playlist.blank(length)
|
||||||
|
|
||||||
|
|
||||||
for clip in data['music']:
|
for clip in data['music']:
|
||||||
frames = int(clip['duration'] * fps)
|
frames = int(clip['duration'] * fps)
|
||||||
if clip.get('blank'):
|
if clip.get('blank'):
|
||||||
|
@ -58,9 +57,11 @@ for clip in data['vocals']:
|
||||||
else:
|
else:
|
||||||
add_clip(vocals, clip['path'], frames)
|
add_clip(vocals, clip['path'], frames)
|
||||||
|
|
||||||
multitrack.connect(music, 0)
|
multitrack.connect(vocals, 0)
|
||||||
multitrack.connect(vocals, 1)
|
multitrack.connect(music, 1)
|
||||||
composite = mlt.Transition(profile, "mix")
|
composite = mlt.Transition(profile, "mix")
|
||||||
|
composite.set("start", 0.01)
|
||||||
|
composite.set("end", 0.01)
|
||||||
composite.set("combine", 1)
|
composite.set("combine", 1)
|
||||||
|
|
||||||
tractor.plant_transition(composite)
|
tractor.plant_transition(composite)
|
||||||
|
|
|
@ -28,6 +28,8 @@ with open(source) as fd:
|
||||||
|
|
||||||
video = mlt.Playlist()
|
video = mlt.Playlist()
|
||||||
overlay = mlt.Playlist()
|
overlay = mlt.Playlist()
|
||||||
|
music = mlt.Playlist()
|
||||||
|
vocals = mlt.Playlist()
|
||||||
|
|
||||||
fps = 60
|
fps = 60
|
||||||
profile = mlt.Profile("atsc_1080p_%d" % fps)
|
profile = mlt.Profile("atsc_1080p_%d" % fps)
|
||||||
|
@ -49,6 +51,14 @@ def add_clip(playlist, file_, in_, duration):
|
||||||
clip.set_in_and_out(in_, in_+duration-1)
|
clip.set_in_and_out(in_, in_+duration-1)
|
||||||
playlist.append(clip)
|
playlist.append(clip)
|
||||||
|
|
||||||
|
def add_audio_clip(playlist, file_, duration):
|
||||||
|
in_ = 0
|
||||||
|
if not isinstance(file_, str):
|
||||||
|
file_ = file_.encode('utf-8')
|
||||||
|
clip = mlt.Producer(profile, file_)
|
||||||
|
clip.set_in_and_out(in_, in_+duration-1)
|
||||||
|
playlist.append(clip)
|
||||||
|
|
||||||
def add_blank(playlist, length):
|
def add_blank(playlist, length):
|
||||||
playlist.blank(length)
|
playlist.blank(length)
|
||||||
|
|
||||||
|
@ -61,6 +71,7 @@ def add_text(playlist, value, length):
|
||||||
text.set('length', length)
|
text.set('length', length)
|
||||||
playlist.append(text)
|
playlist.append(text)
|
||||||
|
|
||||||
|
|
||||||
for clip in data['clips']:
|
for clip in data['clips']:
|
||||||
if clip.get('black'):
|
if clip.get('black'):
|
||||||
# fixme seconds to fps! duration fame etc!!
|
# fixme seconds to fps! duration fame etc!!
|
||||||
|
@ -84,6 +95,20 @@ for clip in data['text']:
|
||||||
frames = int(clip['duration'] * fps)
|
frames = int(clip['duration'] * fps)
|
||||||
add_text(overlay, clip['text'].upper(), frames)
|
add_text(overlay, clip['text'].upper(), frames)
|
||||||
|
|
||||||
|
for clip in data['music']:
|
||||||
|
frames = int(clip['duration'] * fps)
|
||||||
|
if clip.get('blank'):
|
||||||
|
add_blank(music, frames)
|
||||||
|
else:
|
||||||
|
add_audio_clip(music, clip['path'], frames)
|
||||||
|
|
||||||
|
for clip in data['vocals']:
|
||||||
|
frames = int(clip['duration'] * fps)
|
||||||
|
if clip.get('blank'):
|
||||||
|
add_blank(vocals, frames)
|
||||||
|
else:
|
||||||
|
add_audio_clip(vocals, clip['path'], frames)
|
||||||
|
|
||||||
multitrack.connect(video, 0)
|
multitrack.connect(video, 0)
|
||||||
multitrack.connect(overlay, 1)
|
multitrack.connect(overlay, 1)
|
||||||
composite = mlt.Transition(profile, "composite")
|
composite = mlt.Transition(profile, "composite")
|
||||||
|
@ -91,8 +116,50 @@ composite = mlt.Transition(profile, "composite")
|
||||||
|
|
||||||
tractor.plant_transition(composite)
|
tractor.plant_transition(composite)
|
||||||
|
|
||||||
|
volume = mlt.Filter(profile, "volume")
|
||||||
|
volume.set("gain", '0.01')
|
||||||
|
tractor.plant_filter(volume)
|
||||||
|
|
||||||
|
# mix vocals and music
|
||||||
|
|
||||||
|
atractor = mlt.Tractor()
|
||||||
|
atractor.mark_in = -1
|
||||||
|
atractor.mark_out = -1
|
||||||
|
|
||||||
|
audio = atractor.multitrack()
|
||||||
|
audio.connect(vocals, 0)
|
||||||
|
audio.connect(music, 1)
|
||||||
|
mix = mlt.Transition(profile, "mix")
|
||||||
|
mix.set("start", 0.20)
|
||||||
|
mix.set("end", 0.20)
|
||||||
|
atractor.plant_transition(mix)
|
||||||
|
|
||||||
|
# mix video + audio
|
||||||
|
dtractor = mlt.Tractor()
|
||||||
|
dtractor.mark_in = -1
|
||||||
|
dtractor.mark_out = -1
|
||||||
|
dmix = dtractor.multitrack()
|
||||||
|
dmix.connect(atractor, 0)
|
||||||
|
dmix.connect(tractor, 1)
|
||||||
|
|
||||||
|
mix2 = mlt.Transition(profile, "mix")
|
||||||
|
mix2.set("start", 0.5)
|
||||||
|
mix2.set("end", 0.5)
|
||||||
|
dtractor.plant_transition(mix2)
|
||||||
|
|
||||||
|
|
||||||
|
output = mlt.Tractor()
|
||||||
|
tractor.mark_in = -1
|
||||||
|
tractor.mark_out = -1
|
||||||
|
output_tracks = output.multitrack()
|
||||||
|
output_tracks.connect(dtractor, 0)
|
||||||
|
|
||||||
|
norm = mlt.Filter(profile, "volume")
|
||||||
|
norm.set("gain", "-12dB")
|
||||||
|
output.plant_filter(norm)
|
||||||
|
|
||||||
consumer = 'xml'
|
consumer = 'xml'
|
||||||
consumer = mlt.Consumer(profile, consumer, target)
|
consumer = mlt.Consumer(profile, consumer, target)
|
||||||
consumer.connect(tractor)
|
consumer.connect(output)
|
||||||
#consumer.set("real_time", -2)
|
#consumer.set("real_time", -2)
|
||||||
consumer.start()
|
consumer.start()
|
||||||
|
|
Loading…
Reference in a new issue