How to change the treble and bass of an mp3/ogg file? - python

I am aware you can do this via FFmpeg CLI, but I need to do this programmatically. I have tried setting high-pass and low-pass filters using pydub (the module I am using right now) but it kills the program.
My current code:
import os, asyncio, pydub
from pydub import AudioSegment
async def louder(filename:str, tag:bool, testing:bool=False, cb=None):
song = AudioSegment.from_mp3("audios/"+filename.replace(".mp3", "").replace("-", "_")+".mp3")
song = song + 15
song.export("audios/"+filename.replace(".mp3", "").replace("-", "_")+".ogg", format="ogg")
if not testing:
os.unlink(os.path.join(os.getcwd(), "audios/"+filename.replace(".mp3", "").replace("-", "_")+".mp3"))
if cb:
await cb()
if __name__ == "__main__":
async def callback_testing():
print("Done")
asyncio.run(mainAudioBypass(filename="test_mp3", tag=True, testing=True, cb=callback_testing))

Related

How to read RFID tags in one thread and playing audio files in parallel in another thread?

I'm trying to create some sort of Jukebox in Python. The Python code runs on a Raspberry Pi. The setup is as follows
a RFID reader (MFRC522) is connected to the Raspberry Pi correctly (tested) and will read RFID tags with information about a playlist (a list of songs to be played). It is controlled using the SimpleMFRC522 python library
the audio files all reside in a directory ./audio/downloads. The content of the RFID tag will contain the subdirectory for the playlist to be played. (e.g. myPlaylist for ./audio/downloads/myPlaylist). The sound is played using the PyGame Library
some buttons to control the audio are connected to play/pause and skip to the previous/next track. The Buttons are controlled using the Python GPIO Zero library
You can assume the hardware is correctly wired. I checked with some basic scripts (see bottom of this post).
My Python script is this:
# mironibox.py
import threading
from os import listdir
from os.path import isfile, join
import RPi.GPIO as GPIO
from gpiozero import Button
from mfrc522 import SimpleMFRC522
from pygame import mixer
playlist = []
current_track_number = 0
reader = SimpleMFRC522()
button_prev = Button(20)
button_next = Button(16)
button_play_pause = Button(21)
mixer.init()
def read_rfid():
global playlist, current_track_number
while True:
playlist_id, playlist_dir = reader.read()
print(f'read RFID id={playlist_id}: {playlist_dir}')
path = f'./audio/downloads/{playlist_dir.strip()}/'
playlist = sorted([join(path, f) for f in listdir(path) if isfile(join(path, f))])
play(0)
def play(track_number):
global playlist, current_track_number
print(playlist[track_number])
mixer.music.load(playlist[track_number])
mixer.music.play()
current_track_number = track_number
if __name__ == '__main__':
try:
button_prev.when_released = lambda: play(current_track_number - 1)
button_next.when_released = lambda: play(current_track_number + 1)
button_play_pause.when_released = lambda: mixer.music.pause()
rfid = threading.Thread(name='rfid', target=read_rfid, daemon=True)
rfid.start()
print('Waiting for RFID input')
rfid.join() # prevent main thread from exiting
finally:
print('cleaning up')
GPIO.cleanup()
As you can see, the RFID reader is a simple infinite loop that will initialize the playlist array with a list of strings, each one representing the absolute path to a file. I tested with a RFID tag containing the string dieter_wiesenmann_matthias.
This works in a terminal:
$ mplayer ./audio/downloads/dieter_wiesenmann_matthias/01.mp3
... (file is played)
However, when running the script and reading a RFID-tag containing dieter_wiesenmann_matthias, the playlist is created correctly and the mixer is loaded with the correct audio file. But I can hear no sound.
$ python mironibox.py
Waiting for RFID input
/usr/lib/python3/dist-packages/gpiozero/devices.py:288: PinFactoryFallback: Falling back from rpigpio: A different mode has already been set!
warnings.warn(
/usr/lib/python3/dist-packages/gpiozero/devices.py:288: PinFactoryFallback: Falling back from lgpio: No module named 'lgpio'
warnings.warn(
/usr/lib/python3/dist-packages/gpiozero/devices.py:288: PinFactoryFallback: Falling back from rpio: No module named 'RPIO'
warnings.warn(
/usr/lib/python3/dist-packages/gpiozero/devices.py:288: PinFactoryFallback: Falling back from pigpio: No module named 'pigpio'
warnings.warn(
/usr/lib/python3/dist-packages/gpiozero/devices.py:285: NativePinFactoryFallback: Falling back to the experimental pin factory NativeFactory because no other pin factory could be loaded. For best results, install RPi.GPIO or pigpio. See https://gpiozero.readthedocs.io/en/stable/api_pins.html for more information.
warnings.warn(NativePinFactoryFallback(native_fallback_message))
read RFID id=1004807035305: dieter_wiesenmann_matthias
playing: ./audio/downloads/dieter_wiesenmann_matthias/01.mp3
Strangely enough, trying to play the file from the terminal does not work anymore after running the Python script once. I have to reboot the Raspberry to make it work again. Not sure if this is related.
I suspect there's something wrong with the Multithreading, like the main thread being blocked by the RFID-Thread. I'm also not sure about the warnings on the console.
Test scripts I used to check the python code to read an RFID tag or play an audio file
This will print out the content of a RFID tag
import RPi.GPIO as GPIO
from mfrc522 import SimpleMFRC522
reader = SimpleMFRC522()
try:
id, text = reader.read()
print(id)
print(text)
finally:
GPIO.cleanup()
This will play a 5-second test file:
import time
from pygame import mixer
mixer.init()
mixer.music.load('./audio/downloads/dieter_wiesenmann_matthias/01.mp3')
mixer.music.play()
time.sleep(10) # prevent script from exiting before player has played a bit of the file

Python, how to execute a line of code without it stopping the rest of the code from executing?

first of all, im a beginner.
Want i want to accomplish is that music plays while the script is executing.
What it does right now it plays the music, waits until the music is over and then executes the rest of the code. That is not what i want. Here my Code:
import os
import subprocess
import multiprocessing
import threading
from playsound import playsound
CurrentPath = os.path.dirname(os.path.normpath(__file__))
os.chdir(CurrentPath)
def music():
Music = "Music.mp4"
#subprocess.run(["ffplay", "-nodisp", "-autoexit", "-hide_banner", Music])
playsound("Music.mp4")
def other_things():
print("Hello World")
#musicp = multiprocessing.Process(target=music())
#restp = multiprocessing.Process(target=other_things())
musicp = threading.Thread(target=music())
restp = threading.Thread(target=other_things())
restp.start()
musicp.start()
LIke you can see i even tried multithreading but it still waits until the music is over before it goes to the rest of the code.
Don't call the functions in the target parameter of the Thread function - delete the brackets to reference the function, not its return value
musicp = threading.Thread(target=music) # instead of music()
restp = threading.Thread(target=other_things) # instead of other_things()

How to stop audio with playsound module?

How do I stop the audio playing through playaudio module in Python code?
I have played music but I can't stop that music. How can I stop it?
playsound.playsound("name_of_file")
You can use the multiprocessing module to play the sound as a background process, then terminate it anytime you want:
import multiprocessing
from playsound import playsound
p = multiprocessing.Process(target=playsound, args=("file.mp3",))
p.start()
input("press ENTER to stop playback")
p.terminate()
Playsound is a single function module that plays sounds, and nothing else. It would seem that means it does not stop playing sounds either. From their own documentation:
The playsound module contains only one thing - the function (also named) playsound.
Personally, I like to use pyaudio. The following code is adapted from the example here. The code plays audio and has the space bar set as a pause/play button.
import pyaudio
import wave
import time
from pynput import keyboard
paused = False # global to track if the audio is paused
def on_press(key):
global paused
print (key)
if key == keyboard.Key.space:
if stream.is_stopped(): # time to play audio
print ('play pressed')
stream.start_stream()
paused = False
return False
elif stream.is_active(): # time to pause audio
print ('pause pressed')
stream.stop_stream()
paused = True
return False
return False
# you audio here
wf = wave.open('audio\\songs\\And_Your_Bird_Can_Sing_mp3_2_wav.wav', 'rb')
# instantiate PyAudio
p = pyaudio.PyAudio()
# define callback
def callback(in_data, frame_count, time_info, status):
data = wf.readframes(frame_count)
return (data, pyaudio.paContinue)
# open stream using callback
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
channels=wf.getnchannels(),
rate=wf.getframerate(),
output=True,
stream_callback=callback)
# start the stream
stream.start_stream()
while stream.is_active() or paused==True:
with keyboard.Listener(on_press=on_press) as listener:
listener.join()
time.sleep(0.1)
# stop stream
stream.stop_stream()
stream.close()
wf.close()
# close PyAudio
p.terminate()
On windows try:
import winsound
winsound.PlaySound(r'C:\sound.wav', winsound.SND_ASYNC)
Stop Playback:
winsound.PlaySound(None, winsound.SND_PURGE)
#pip install pygame
from pygame import mixer
import time
mixer.init() #Initialzing pyamge mixer
mixer.music.load('lovingly-618.mp3') #Loading Music File
mixer.music.play() #Playing Music with Pygame
time.sleep(5)
mixer.music.stop()
Here is a much easier way:
wmp = win32com.client.dynamic.Dispatch("WMPlayer.OCX")
wmp.settings.autoStart = True
wmp.settings.volume = 100
wmp.URL = file
while globals()["allowSound"]:
PumpWaitingMessages()
You can change globals()["allowSound"] from another thread and set it to false when the audio has ended (you can get the length of the audio with wmp.durationString)
Here is some more info about this: Windows Media Player COM Automation works from VBS but not from Python
Although this does not use the playsound module it is a good alternative.
After successful execution of the program, audio file will start playing. Now Click on terminal, once you see the cursor, type Ctrl+C, it will bring you out of the terminal and audio will also stop playing.
Programming Instructions used:
from playsound import playsound
playsound('//path//to//a//sound//file//you//want//to//play.mp3')
EASY......
on your terminal tab, look for kill(delete) option on the right hand side.
click the delete option and it will stop playing

readline python module does not work with aioconsole.ainput

The following code accepts input from terminal and echo it back:
import readline
import asyncio
import aioconsole
async def input_coro():
while True:
from_user = await aioconsole.ainput('> ')
from_user = from_user.strip()
print(from_user)
if __name__ == "__main__":
asyncio.get_event_loop().run_until_complete(input_coro())
However import readline has not effect here, meaning using up/down arrows to go through the command line history does not work.
How can I get the readline functionality with aioconsole.ainput ?

Error while re-opening sound file in python

I was in the process of making a program that simply repeats any text you enter, and seemed to be working when I first tested it. The problem is that the second time I attempt to type anything, it crashes and says that permission was denied to the sound file I was recording it to. I believe it is because the file was already opened, but none the less I do not know how to fix it. I am using the gTTS and Pygame modules.
from gtts import gTTS
from tempfile import TemporaryFile
from pygame import mixer
#Plays Sound
def play():
mixer.init()
mixer.music.load("Speech.mp3")
mixer.music.play()
#Voice
def voice(x):
text = gTTS(text= x, lang= 'en')
with open("Speech.mp3", 'wb') as f:
text.write_to_fp(f)
f.close()
play()
#Prompts user to enter text for speech
while True:
voice_input = input("What should Wellington Say: ")
voice(voice_input)
Figured it out. I added this function:
def delete():
sleep(2)
mixer.music.load("Holder.mp3")
os.remove("Speech.mp3")
And call it after .play(), so it now simply deletes the file when it is done and then re-creates it when you need to use it next.
To expand on my comment above (with help from this thread), I think play() may be locking the file. You can manually try the following:
def play():
mixer.init()
mixer.music.load("Speech.mp3")
mixer.music.play()
while pygame.mixer.music.get_busy():
pygame.time.Clock().tick(10)
or
def play():
mixer.init()
mixer.music.load("Speech.mp3")
mixer.music.play()
mixer.music.stop()
But this second fix might have the consequence of not hearing anything played back.
I fixed the problem by writing to a temporary file and using os.rename:
from gtts import gTTS
from pygame import mixer
import os
play_name = 'Speech.mp3'
save_name = "%s.%s" % (play_name, '.tmp')
def play():
mixer.music.load(play_name)
mixer.music.play()
def voice(x):
text = gTTS(text=x, lang='en')
with open(save_name, 'wb') as tmp_file:
text.write_to_fp(tmp_file)
os.rename(save_name, play_name)
try:
mixer.init()
while True:
voice_input = raw_input("What should Wellington Say: ")
voice(voice_input)
play()
except KeyboardInterrupt:
pass
I ran a test where I typed in a very long sentence and then another sentence while the first one was playing and everything still worked.

Categories

Resources