hpr3496 :: How I record HPR Episodes
Some python to record short segments of audio.
Hosted by norrist on Monday, 2021-12-27 is flagged as Clean and is released under a CC-BY-SA license.
python, sox.
3.
The show is available on the Internet Archive at: https://archive.org/details/hpr3496
Listen in ogg,
spx,
or mp3 format. Play now:
Duration: 00:28:27
general.
https://gitlab.com/norrist/solocast
Sample script.txt
This is a sample script for solocast.
Separate the segments with a blank line
Bulleted lists are OK, but keep the items together by not skipping a line
- Item 1
- Item 2
### Markdown Formatting is OK
But the Formatting gets lost in the script
so you can write show notes in loosely formatted markdown
Don't have more than 1 blank line separating segments
solocast.py
#! /usr/bin/env python3
import click
import os
from shutil import which
script_file = "script.txt"
recording_directory_name = "Recordings"
recording_format = "wav"
script_segments = {}
def test_sox_exists():
try:
assert which("sox")
except AssertionError:
print("Cant find sox. Install sox somewhere in your path.")
exit(1)
def get_recording_file_name(slug):
return f"{recording_directory_name}/{slug}.{recording_format}"
def project_prep():
if not os.path.exists(recording_directory_name):
os.makedirs(recording_directory_name)
if not os.path.exists(f"{recording_directory_name}/Archive"):
os.makedirs(f"{recording_directory_name}/Archive")
def wait_for_input():
click.echo("*" * 40)
_ = input("Press ENTER to Continue")
def add_slug_text(slug, text):
script_segments[slug] = text
def recording_exists(slug):
if os.path.isfile(get_recording_file_name(slug)):
return True
return False
def noise_profile_missing():
if os.path.isfile(f"{recording_directory_name}/noise.prof"):
return False
return True
def truncate_audio(slug):
recording = get_recording_file_name(slug)
new_recording = f"{recording_directory_name}/{slug}-truncated.{recording_format}"
click.echo(f"truncating {recording}")
SOX_CMD = (
f"sox -V2 {recording} {new_recording} silence -l 1 0.1 .1% -1 1.0 .1% stat"
)
click.echo(SOX_CMD)
os.system(SOX_CMD)
os.system(
f" mv -v {recording} {recording_directory_name}/Archive/{slug}.{recording_format}"
)
os.rename(new_recording, recording)
review_audio(slug)
def play_audio(slug):
recording = get_recording_file_name(slug)
click.echo(f"Playing {recording}")
os.system(f"play {recording}")
review_audio(slug)
def delete_audio(slug):
recording = get_recording_file_name(slug)
os.remove(recording)
def review_audio(slug):
review_menu = ["(p)lay", "(a)ccept", "(r)eccord again", "(t)runcate"]
click.echo(slug)
for i in review_menu:
click.echo(i)
menu_action = input(">> ")
if menu_action == "p":
play_audio(slug)
elif menu_action == "a":
exit()
elif menu_action == "r":
delete_audio(slug)
find_and_record_next()
elif menu_action == "t":
truncate_audio(slug)
else:
review_audio(slug)
def record_audio(slug):
new_recording = get_recording_file_name(slug)
click.echo(f"Creating {new_recording}")
click.echo("press Enter to start then CRTL-C to quit")
wait_for_input()
os.system(f"rec {new_recording}")
def record_silent_audio():
silent_recording = f"{recording_directory_name}/silence.{recording_format}"
click.echo("RECORD 5 SECONDS OF SILENCE \n" * 5)
click.echo("press Enter to start")
wait_for_input()
os.system(f"rec {silent_recording} trim 0 5")
os.system(
f"sox {silent_recording} -n noiseprof {recording_directory_name}/noise.prof"
)
def load_script():
linetext = ""
with open(script_file) as script_file_reader:
for line in script_file_reader.readlines():
if not line.strip():
slug = linetext[:40].title()
segment_name = "".join(filter(str.isalnum, slug))
add_slug_text(segment_name, linetext)
linetext = ""
else:
linetext += f"{line} \n"
def combine_recordings_for_export():
recording_list = []
combined_recording = f"{recording_directory_name}/combined.{recording_format}"
for slug, text in script_segments.items():
recording = get_recording_file_name(slug)
recording_list.append(recording)
recording_list_string = " ".join(recording_list)
print(recording_list_string)
SOX_CMD = f"sox -V3 {recording_list_string} {combined_recording} noisered {recording_directory_name}/noise.prof 0.21 norm -10"
click.echo(SOX_CMD)
os.system(SOX_CMD)
def find_and_record_next():
for slug, text in script_segments.items():
if recording_exists(slug):
continue
click.clear()
click.echo(slug)
click.echo("*" * 40)
click.echo(text)
click.echo("*" * 40)
record_audio(slug)
review_audio(slug)
@click.group()
def cli():
test_sox_exists()
pass
@cli.command()
def combine():
"Combine Segments into single audio file"
combine_recordings_for_export()
@cli.command()
def record():
"Record next unrecorded segment"
if noise_profile_missing():
record_silent_audio()
find_and_record_next()
@cli.command()
def silence():
"Generate noise profile"
record_silent_audio()
@cli.command()
def review():
"Print segments"
for slug, text in script_segments.items():
click.clear()
click.echo(slug)
click.echo("*" * 40)
click.echo()
click.echo(text)
wait_for_input()
if __name__ == "__main__":
project_prep()
load_script()
cli()