def play_song(name, url):
"""
Function that plays a song in a new thread
Args:
name (str): Name to display
url (str): URL to fetch the mp3 from
"""
global current_song
global playback_progress
current_song = 'Loading...' # Set the song name to 'Loading...' to notify the user
playback_progress = 0
wav = download_mp3_to_wav(url) # Download the mp3 file as a wav from jetsetradio.live
if not wav: # If there's no wav returned, don't play it
return
current_song = name # Set the song name to the new song
pa = pyaudio.PyAudio() # Main class of pyAudio; contains the open() function we need for an audio stream
# Opens an audio stream on the default output device.
# Explained: We're using 1/2th the framerate because we're going from Int16 to Float32; this change
# requires us to get twice the amount of data, hence leaving us with twice the amount of bytes.
# We convert from Int16 to Float32 to prevent byte overflow, which results in garbled (and scary) static.
audio_stream = pa.open(wav.getframerate() // 2, wav.getnchannels(), pyaudio.paFloat32, output=True)
audio_stream.start_stream()
buffer_size = audio_stream._frames_per_buffer # The amount of int16's to read per frame
while True:
data = wav.readframes(buffer_size * 2) # Read data from wav
if isinstance(data, str): # Check typing to prevent errors
data = data.encode('utf-8')
# Take each byte, divide by 0x7FFF to get a float, and then multiply that by the volume constant
data = struct.pack('f' * (len(data) // 2), *list(map(lambda b: b / 65535 * (volume / 9),
struct.unpack('H' * (len(data) // 2), data))))
playback_progress = wav.tell() / wav.getnframes() # Set percent of song played
audio_stream.write(data) # Write raw data to speakers
if len(data) // 2 < buffer_size: # If we're out of data, exit the loop
break
if current_song != name: # If the song changed halfway through, stop the stream
break
audio_stream.stop_stream()
del audio_stream # Cleanup unused variables
del pa
del wav
# Main code
评论列表
文章目录