musicmuster/archive/audplayer.py
2024-04-05 10:41:14 +01:00

226 lines
6.3 KiB
Python
Executable File

#!/usr/bin/python3
import datetime as dt
from threading import Timer
from pydub import AudioSegment
from time import sleep
from timeloop import Timeloop # type: ignore
import vlc # type: ignore
class RepeatedTimer(object):
def __init__(self, interval, function, *args, **kwargs):
self._timer = None
self.interval = interval
self.function = function
self.args = args
self.kwargs = kwargs
self.is_running = False
self.start()
def _run(self):
self.is_running = False
self.start()
self.function(*self.args, **self.kwargs)
def start(self):
if not self.is_running:
self._timer = Timer(self.interval, self._run)
self._timer.start()
self.is_running = True
def stop(self):
self._timer.cancel()
self.is_running = False
tl = Timeloop()
def leading_silence(audio_segment, silence_threshold=-50.0, chunk_size=10):
"""
Returns the millisecond/index that the leading silence ends.
audio_segment - the segment to find silence in
silence_threshold - the upper bound for how quiet is silent in dFBS
chunk_size - chunk size for interating over the segment in ms
https://github.com/jiaaro/pydub/blob/master/pydub/silence.py
"""
trim_ms = 0 # ms
assert chunk_size > 0 # to avoid infinite loop
while audio_segment[
trim_ms : trim_ms + chunk_size
].dBFS < silence_threshold and trim_ms < len(audio_segment):
trim_ms += chunk_size
# if there is no end it should return the length of the segment
return min(trim_ms, len(audio_segment))
def significant_fade(audio_segment, fade_threshold=-20.0, chunk_size=10):
"""
Returns the millisecond/index of the point where the fade is down to
fade_threshold and doesn't get louder again.
audio_segment - the segment to find silence in
fade_threshold - the upper bound for how quiet is silent in dFBS
chunk_size - chunk size for interating over the segment in ms
"""
assert chunk_size > 0 # to avoid infinite loop
segment_length = audio_segment.duration_seconds * 1000 # ms
trim_ms = segment_length - chunk_size
while (
audio_segment[trim_ms : trim_ms + chunk_size].dBFS < fade_threshold
and trim_ms > 0
):
trim_ms -= chunk_size
# if there is no trailing silence, return lenght of track (it's less
# the chunk_size, but for chunk_size = 10ms, this may be ignored)
return trim_ms
def trailing_silence(audio_segment, silence_threshold=-50.0, chunk_size=10):
"""
Returns the millisecond/index that the trailing silence starts.
audio_segment - the segment to find silence in
silence_threshold - the upper bound for how quiet is silent in dFBS
chunk_size - chunk size for interating over the segment in ms
"""
assert chunk_size > 0 # to avoid infinite loop
segment_length = audio_segment.duration_seconds * 1000 # ms
trim_ms = segment_length - chunk_size
while (
audio_segment[trim_ms : trim_ms + chunk_size].dBFS < silence_threshold
and trim_ms > 0
):
trim_ms -= chunk_size
# if there is no trailing silence, return lenght of track (it's less
# the chunk_size, but for chunk_size = 10ms, this may be ignored)
return trim_ms
def ms_to_mmss(ms, decimals=0):
if not ms:
return "-"
if ms < 0:
sign = "-"
else:
sign = ""
minutes, remainder = divmod(ms, 60 * 1000)
seconds = remainder / 1000
return f"{sign}{minutes:.0f}:{seconds:02.{decimals}f}"
# @tl.job(interval=timedelta(seconds=1))
def update_progress(player, talk_at, silent_at):
elapsed_time = player.get_time()
total_time = player.get_length()
remaining_time = total_time - elapsed_time
talk_time = remaining_time - (total_time - talk_at)
silent_time = remaining_time - (total_time - silent_at)
end_time = (dt.datetime.now() + timedelta(milliseconds=remaining_time)).strftime(
"%H:%M:%S"
)
print(
f"\t{ms_to_mmss(elapsed_time)}/"
f"{ms_to_mmss(total_time)}\t\t"
f"Talk in: {ms_to_mmss(talk_time)} "
f"Silent in: {ms_to_mmss(silent_time)} "
f"Ends at: {end_time} [{ms_to_mmss(remaining_time)}]",
end="\r",
)
# Print name of current song, print name of next song. Play current when
# return pressed, Pri--current-song-output-lengthnt remaining time every
# second. When it ends, print name of new current and next song.
def test():
track = "wibg.mp3"
segment = AudioSegment.from_mp3(track)
print(f"Track: {track}")
print(f"Leading silence: {ms_to_mmss(leading_silence(segment), decimals=1)}")
talk_at = significant_fade(segment)
silent_at = trailing_silence(segment)
print(f"Talkover fade: {ms_to_mmss(talk_at)}")
print(f"Track silent from: {ms_to_mmss(silent_at)}")
p = vlc.MediaPlayer("wibg.mp3")
_ = input("")
p.play()
print()
rt = RepeatedTimer(0.5, update_progress, p, talk_at, silent_at)
sleep(1)
while p.is_playing():
sleep(1)
rt.stop() # better in a try/finally block to make sure the program ends!
print("End")
test()
# next_song = get_next_song
#
# def play_track():
# r = run_aud_cmd("--current-song-length
#
#
#
# def play():
# play_track()
# songtimer_start()
#
#
# print("Start playing in 3 seconds")
#
# sleep(3)
#
# play()
# print("starting...")
# This auto-starts, no need of rt.start()
# rt = RepeatedTimer(0.3, hello, "World")
#
# count = 5
# while count > 0:
# print("main job here")
# sleep(2)
# rt.stop() # better in a try/finally block to make sure the program ends!
# #!/usr/bin/python3
#
# import time
# from timeloop import Timeloop
# from datetime import timedelta
#
# tl = Timeloop()
#
# @tl.job(interval=timedelta(seconds=2))
# def sample_job_every_2s():
# print(f"2s job current time: {time.ctime()}")
#
# @tl.job(interval=timedelta(seconds=5))
# def sample_job_every_5s():
# print(f"5s job current time: {time.ctime()}")
#
# @tl.job(interval=timedelta(seconds=10))
# def sample_job_every_10s():
# print(f"10s job current time: {time.ctime()}")
#
# @tl.job(interval=timedelta(seconds=0.2))
# def sample_job_every_10s():
# print(f"200ms job current time: {time.ctime()}")
#
# if __name__ == "__main__":
# tl.start(block=True)
#