Skip to content

Instantly share code, notes, and snippets.

@Nircek
Last active December 24, 2021 22:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Nircek/72c2fb9e811df0a0fa67599ab0f79754 to your computer and use it in GitHub Desktop.
Save Nircek/72c2fb9e811df0a0fa67599ab0f79754 to your computer and use it in GitHub Desktop.
split audio files not evenly
#!/usr/bin/env python3
# Copyright 2021 Marcin Zepp <nircek-2103@protonmail.com>
# SPDX-License-Identifier: MIT
import sys
import subprocess
import re
import math
opus, oldmagic, quiet, magic = False, False, True, True
TARGET = 1e-2
assert len(sys.argv) >= 2
for arg in sys.argv[1:-1]:
if arg == '-opus':
opus = True
elif arg == '-nomagic':
magic = False
elif arg == '-debug':
quiet = False
elif arg == '-oldmagic':
oldmagic = True
else:
raise Exception(f'arg `{arg}` not known')
inp = sys.argv[-1]
def nice(x):
return f'{int(x/3600)}:{int((x%3600)/60):02d}:{x%60:05.2f}'
def getDuration(file):
return float(re.search(b'\nduration=([\d.]+)\n', subprocess.check_output([*'ffprobe -v error -show_format -show_streams'.split(), file])).group(1).decode())
duration = getDuration(inp)
print(f'Duration: {nice(duration)} ({duration})')
i = 2
while i <= 10 or ms > 3*60:
print(f'{i})', end='\t')
s = (duration-i*(i-1)//2)/i # sum(range(i))
ms = s + i - 1
print(nice(s), end=' \t')
print(nice(ms))
i += 1
parts = int(input(':'))
print()
inps = inp.split('.')
name, ext = '.'.join(inps[:-1]), inps[-1]
last = None
MAGIC_OFFSET = 0
if oldmagic:
MAGIC_OFFSET = (duration*(1/122-(1/(parts**3))/2.4)*math.log(parts)+duration/100*8)/1000 if magic else 0
elif magic:
print('init', end='(')
for i in range(1, 5):
off = (duration+MAGIC_OFFSET-parts*(parts-1)//2)/parts
ss = (parts-1)*(off+(parts-2)/2)
exp = off+parts-1
ss = f'{ss}'
sys.stdout.flush()
outp = f'{name}-0.{ext}'
outo = f'{name}-0.opus'
if not opus:
subprocess.call(['ffmpeg', '-loglevel', 'quiet', '-hide_banner', '-y', '-ss', ss, '-i', inp, '-c', 'copy', outp])
last = outp
else:
# https://stackoverflow.com/a/39671913/6732111
subprocess.call(['ffmpeg', '-loglevel', 'quiet', '-hide_banner', '-y', '-ss', ss, '-i', inp, *'-f wav -flags +bitexact -acodec pcm_s16le -ar 22050 -ac 1'.split(), outp])
subprocess.call(['opusenc', '--quiet', outp, outo], stderr=subprocess.DEVNULL if quiet else None)
subprocess.call(['rm', outp])
last = outo
dur = getDuration(last)
subprocess.call(['rm', last])
print(f'{"" if i == 1 else "=>"}{dur-exp:.4f}', end='')
if abs(dur-exp) < TARGET:
break
MAGIC_OFFSET += (dur-exp)/i/i
sys.stdout.flush()
# for e in *.opus; do ffprobe -i $e -show_entries format=duration -v quiet -of csv="p=0"; done
print(')')
print(f'Using {MAGIC_OFFSET=}.\n')
off = (duration+MAGIC_OFFSET-parts*(parts-1)//2)/parts
exp = off+parts-1
last = None
for i in range(parts):
ss = i*off+(i-1)*i//2
t = off+i
e = ss + t
ss, t = [f'{x}' for x in [ss, t]]
print(f'{100*i//parts}%', end=' ' if quiet else '\n')
if quiet:
sys.stdout.flush()
outp = f'{name}-{str(i+1)}.{ext}'
outo = f'{name}-{str(i+1)}.opus'
if not opus:
subprocess.call(['ffmpeg', *(['-loglevel', 'quiet', '-hide_banner'] if quiet else []), '-y', '-ss', ss, '-i', inp, '-c', 'copy', *(['-t', t] if i != parts-1 else []), outp])
last = outp
else:
# https://stackoverflow.com/a/39671913/6732111
subprocess.call(['ffmpeg', *(['-loglevel', 'quiet', '-hide_banner'] if quiet else []), '-y', '-ss', ss, '-i', inp, *'-f wav -flags +bitexact -acodec pcm_s16le -ar 22050 -ac 1'.split(), *(['-t', t] if i != parts-1 else []), outp])
subprocess.call(['opusenc', *(['--quiet'] if quiet else []), outp, outo], stderr=subprocess.DEVNULL if quiet else None)
subprocess.call(['rm', outp])
last = outo
print('100%\n')
if last is not None:
dur = getDuration(last)
print(f'Missed target by {dur-exp:.4f} s (was {dur:.4f}, expected {exp:.4f}).')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment