changing speed of song while its playing and have the changed effects in the song using python - python

i want to change the tempo of music that is playing and reflect it into the currently playing song so if i want i can change the tempo while the song is playing.
from pydub import *
from pydub.playback import play
sound = AudioSegment.from_wav('mymusic.wav')
newsound = sound.speedup(playback_speed=2)
play(newsound)`
this code doesn't let me interfere with the music playing it does the job after the music is played completely and i want to interfere with the music playing currently and have the changed tempo as the music plays along

from pydub import AudioSegment
from pydub.playback import _play_with_sounddevice
sound = AudioSegment.from_wav('mymusic.wav')
# set the initial tempo change factor
tempo_change = 1.0
# define a callback function to process audio blocks in real-time
def tempo_callback(indata, frames, time, status):
global tempo_change
# stretch the audio to change the tempo without changing the pitch
outdata = indata.copy().time_stretch(tempo_change)
return outdata, pyaudio.paContinue
# play the audio with the callback function
_play_with_sounddevice(sound, tempo_callback=tempo_callback)

Related

PySImpleGUI -> How to play audio in the Background

I'm using PySimpleGUI for creation of a simple program where a music should be played in the background of the GUI, but the problem is that Audio is played first and after that only the GUI appears, Is there any method to solve this Issue ?
Here I'm using pydub for playing audio since others may result in an error when converted to .exe
from pydub import AudioSegment
from pydub.playback import play
from PySimpleGUI import *
st="W"
if st=="W":
path_to_file="congratulation.mp3"
song = AudioSegment.from_mp3(path_to_file)
elif st=="F":
path_to_file="fail.mp3"
song = AudioSegment.from_mp3(path_to_file)
layout=[[Text("You've "+st)],[Button("OK")]]
window=Window("Test",layout)
while True:
play(song)
e,v=window2.read()
if e==None or e=="OK":
exit()
Example code to play mp3, but only for non-stop play even after window closed, or next song played. Bugs or functions of pydub ignored here.
import threading
from pathlib import Path
from pydub import AudioSegment
from pydub.playback import play
import PySimpleGUI as sg
font = ('Courier New', 11)
sg.theme('DarkBlue3')
sg.set_options(font=font)
layout = [
[sg.Text('Song file to play')],
[sg.Input(enable_events=True, key='-SONG-'),
sg.FileBrowse(file_types=(("All MP3 Files", "*.mp3"),))],
[sg.Button('Play'), sg.Button('Exit')],
]
window = sg.Window("Pydub MP3 Player", layout, finalize=True)
song = None
while True:
event, values = window.read()
if event in (sg.WINDOW_CLOSED, 'Exit'):
break
elif event == '-SONG-':
path_to_file = values['-SONG-']
if Path(path_to_file).is_file():
try:
song = AudioSegment.from_mp3(path_to_file)
except:
pass
elif event == 'Play':
if song:
threading.Thread(target=play, args=(song,), daemon=True).start()
window.close()
I believe the easiest way to solve your problem would be to create a thread that plays the sound.
import threading as thread
# Your code
while True:
thread.start_new_thread(play, (song, ))
# The rest of your code
The above should work, if what you wanted to do was to play the sound in the background while the program kept going. This wouldn't allow you to stop the sound in the middle, however, and it could feasibly play several overlapping instances of the sound if the loop runs several times in quick succession.
Pydub has a closed issue regarding something similar: https://github.com/jiaaro/pydub/issues/160
The answer there is a bit more comprehensive than what you asked for in your question, though.
Edited to add: I believe there are other, non-default players that does this or something similar by default, but if the sound is a simple, uplifting "ding" or a sad buzzer, more complex solutions could be superfluous.

How to get out of the while loop in Pygame when after playing the music?

I have the code down below actually what I want that when one the music get finished it should get out of the while loop automatically. But it isn't getting out of that and if I remove that while loop the song is not getting played.
from pygame import mixer
def mplayer(name):
''' for playing music '''
mixer.init()
mixer.music.load(name)
mixer.music.set_volume(0.7)
mixer.music.play()
mplayer('welcome.mp3')
while True:
continue
Is there any way that once the music is finished than it should get out the loop?
Use mixer.music.get_busy() to test test if any sound is being mixed.
from pygame import mixer
def mplayer(name):
''' for playing music '''
mixer.init()
mixer.music.load(name)
mixer.music.set_volume(0.7)
mixer.music.play()
mplayer('welcome.mp3')
while mixer.music.get_busy():
# you may have to handle the events here
# pygame.event.pump()
# [...]
pass
Note, you may need to handle the events in the loop that is waiting for the music to finish. See pygame.event.get() respectively pygame.event.pump():
For each frame of your game, you will need to make some sort of call to the event queue. This ensures your program can internally interact with the rest of the operating system.
PyGame has 2 different modules for playing sound and music, the pygame.mixer module and the pygame.mixer.music module. This module contains classes for loading Sound objects and controlling playback. The difference is explained in the documentation:
The difference between the music playback and regular Sound playback is that the music is streamed, and never actually loaded all at once. The mixer system only supports a single music stream at once.
If pygame.mixer.music doesn't work for you try pygame.mixer.music:
from pygame import mixer
def mplayer(name):
''' for playing music '''
mixer.init()
my_sound = mixer.Sound(name)
my_sound.set_volume(0.7)
my_sound.play(0)
mplayer('welcome.mp3')
while mixer.get_busy():
# you may have to handle the events here
# pygame.event.pump()
# [...]
pass
Here is the solution of my own problem:↓
from pygame import mixer
def mplayer(name):
''' for playing music '''
mixer.init()
mixer.music.load(name)
mixer.music.set_volume(0.7)
mixer.music.play()
mplayer('welcome.mp3')
while mixer.music.get_busy(): #just changed this line
pass

How would I be able to pan a sound in pygame?

Basically, what I want to accomplish here, is a way to pan the sound while the game is running. I'd like to make the volumes (left and right) change depending on the position of the player. For now I've got a simple code that I thought that would be a good test:
pygame.mixer.init()
self.sound = pygame.mixer.Sound("System Of A Down - DDevil #06.mp3")
print("I could get here")
self.music = self.sound.play()
self.music.set_volume(1.0, 0)
First, I tried something similar but with pygame.mixer.music, but I came to realize that there's no way to change the volumes separately this way, or so I think, then I changed to the code presented here.
Now it seems like the file is not able to be loaded, my guess is that the file is too big to be treated as a sound in pygame. Any idea of how I'd be able to make this work?
You can pan on the Channel like this:
from os import split, join
import pygame
import pygame.examples.aliens
pygame.init()
# get path to an example punch.wav file that comes with pygame.
sound_path = join(split(pygame.examples.aliens.__file__)[0], 'data', 'punch.wav')
sound = pygame.mixer.Sound(sound_path)
# mixer can mix several sounds together at once.
# Find a free channel to play the sound on.
channel = pygame.mixer.find_channel()
# pan volume full loudness on the left, and silent on right.
channel.set_volume(1.0, 0.0)
channel.play(sound)
https://www.pygame.org/docs/ref/mixer.html#pygame.mixer.Channel
It may be worth looking into a seperate audio library for this. In general i'd recommend PortAudio (which is C), but using the python bindings for it provided by PyAudio. This will give you much more control over the exact audio stream.
To simplify this even further, there is a library known as PyDub which is built ontop of PyAudio for a high level interface (it even has a specific pan method!).
from pydub import AudioSegment
from pydub.playback import play
backgroundMusic = AudioSegment.from_wav("music.wav")
# pan the audio 15% to the right
panned_right = backgroundMusic.pan(+0.15)
# pan the audio 50% to the left
panned_left = backgroundMusic.pan(-0.50)
#Play audio
while True:
try:
play(panned_left)
#play(panned_right)
If this is too slow or doesn't provide effective real-time implementations then I would definately give PyAudio a go because you will also learn a lot more about audio processing in the process!
PS. if you do use PyAudio make sure to check out the callback techniques so that the game you are running can continue to run in parallel using different threads.
This answer certainly can help you.
Basically, you get the screen width, then you pan the left according to player.pos.x / screen_width, and the right according to 1 - player.pos.y / screen_width like that:
Pseudocode:
channel = music.play() # we will pan the music through the use of a channel
screen_width = screen.get_surface().get_width()
[main loop]:
right = player.pos.x / screen_width
left = player.pos.x / screen_width
channel.set_volume(left, right)
Documentation:
pygame.mixer.Channel
pygame.mixer.Sound
pygame.mixer.Channel.set_volume

Pygame mixer only plays one sound at a time

Here is my code:
pygame.mixer.init(frequency=22050,size=-16,channels=4)
sound1 = pygame.mixer.Sound('sound1.wav')
sound2 = pygame.mixer.Sound('sound2.wav')
chan1 = pygame.mixer.find_channel()
chan2 = pygame.mixer.find_channel()
chan1.queue(sound1)
chan2.queue(sound2)
time.sleep(10)
I would think it would play sound1 and sound2 simultaneously (queue is non-blocking and the code immediately hits the sleep).
Instead, it plays sound1 and then plays sound2 when sound1 is finished.
I've confirmed both channels are distinct objects in memory so find_channel isn't returning the same channel. Is there something I'm missing or does pygame not handle this?
See Pygame Docs, It says:
Channel.queue - queue a Sound object to follow the current
So, even though your tracks are playing on different channels, so if you force each sound to play, they will play simultaneously.
And for playing multiple sounds:
Open all sound files, and add the mixer.Sound object to a list.
The loop through the list, and start all the sounds.. using sound.play
This forces all the sounds to play simultaneously.
Also, make sure that you have enough empty channels to play all sounds, or else, some or the other sound sound will be interrupted.
So in code:
sound_files = [...] # your files
sounds = [pygame.mixer.Sound(f) for f in sound_files]
for s in sounds:
s.play()
You could also create a new Channel or use find_channel() for each sound..
sound_files = [...] # your files
sounds = [pygame.mixer.Sound(f) for f in sound_files]
for s in sounds:
pygame.mixer.find_channel().play(s)
The only thing i can think of is that chan1 and chan2 are same, even though they are different objects, they can be pointing to the same channel.
Try queueing right after getting a channel, that way you are sure to get a different channel with find_channel(), since find_channel() always returns a non-busy channel.
Try this:
pygame.mixer.init(frequency=22050,size=-16,channels=4)
sound1 = pygame.mixer.Sound('sound1.wav')
sound2 = pygame.mixer.Sound('sound2.wav')
chan1 = pygame.mixer.find_channel()
chan1.queue(sound1)
chan2 = pygame.mixer.find_channel()
chan2.queue(sound2)
time.sleep(10)

Find the Length of a Song with Pygame

I'm building an Radio Automation Program, but I can't figure out how to have a timer countdown the number of seconds left in the song. I'm currently using Pygame and don't really want to load another toolkit just for this. So far I can make a timer count up using this:
import pygame
#setup music
track = "Music/Track02.wav"
pygame.mixer.music.load(track)
pygame.mixer.music.play()
print("Playing Music")
while(pygame.mixer.music.get_busy()):
print "\r"+str(pygame.mixer.music.get_pos()),
But I have no idea how to get the total length of the song and countdown without having played the song already.
You could also load the song as a normal sound and then check the length while using mixer.music for playing it.
a = pygame.mixer.Sound("test.wav")
print("length",a.get_length())
The mutagen.mp3 can be used to find the length of music.
Firstly: pip install mutagen
-> İmport:
from pygame import *
from mutagen.mp3 import MP3
-> Use:
mixer.music.load('example.mp3')
song = MP3('example.mp3')
songLength = song.info.length
Check the Documentation. According to the site, this function returns the length of a sound object in seconds. So, time remaining is simply (pygame.mixer.music.get_length() - pygame.mixer.music.get_pos())*-1.
That way, it displays as a negative number like most time remaining counters do in a music player. Note, I don't have pygame on this computer, so I can't test it. So, check it just to make sure.

Categories

Resources