Loading and playing music in python - python

So i'm trying to play music on pygame and so far I can successfully load and play the music on the program, but I can do that without variables and i'm not sure how to do it with variables involved.
I've already tried to store them inside a variable and playing them from the variable.
Menumusic = pygame.mixer.music.load("MainMenu.mp3")
Menumusic.play(-1, 0.0)
I expect the music to play but instead i get this as the output:
Menumusic.play(-1, 0.0)
AttributeError: 'NoneType' object has no attribute 'play'

According to the documentation you should call pygame.mixer.music.play() to start playback of the loaded music stream.

It's not very clear what you mean by playing from a variable but it seems to me that you want to change what music is played. You can't do without your variable Menumusic because it contains all the functionality needed to play the music.
myvariablemp3 = "MainMenu.mp3" # Change this to some way of varying the filename
Menumusic = pygame.mixer.music.load(myvariablemp3)
Menumusic.play(-1, 0.0)

Generally to hold a sound in a variable, the code needs to use pygame.mixer.Sound() to load the file in.
For example:
drum_beat = pygame.mixer.Sound("bass_drum.wav")
Later on in the code, the pre-loaded sound can be played by passing the result from that .Sound(...) call (in this case drum_beat) to pygame.mixer.Sound.play().
drum_beat = pygame.mixer.Sound("bass_drum.wav")
...
pygame.mixer.Sound.play( drum_beat )

Related

Why does pygame.mixer.Sound().play() return None?

According to the pygame documentation, pygame.mixer.Sound().play() should return a Channel object. It actually does.
But sometimes, it seems to return None because the very next line, I get this error:
NoneType has no attribute set_volume
when I try to type
channel = music.play(-1)
channel.set_volume(0.5)
Of course the error can happen because the sound is very short, but the error can't come from there (Is 5'38" shorter than the time python needs to shift from one line to the next?)
I also Ctrl+H all the code to see if I typed somewhere channel = None (because I use multiple threads) - Nothing.
Does anybody had the same problem? Is that a pygame bug?
I use python 3.8.2, pygame 2.0.1 and Windows.
Currently I bypass the error rather than fix it like that:
channel = None
while channel is None:
channel = music.play()
channel.set_volume(0.5)
But... it doesn't seem to help very much: the game freezes, because pygame constantly returns None.
Sound.play() returns None if it can't find a channel to play the sound on, so you have to check the return value. Using the while loop is obviously a bad idea.
Note that you can either set the volumne of not only an entire Channel, but also on a Sound object, too. So you could set the volume of your music sound before trying to play it:
music.set_volume(0.5)
music.play()
If you want to make sure that Sound is played, you should get a Channel before and use that Channel to play that Sound, something like this:
# at the start of your game
# ensure there's always one channel that is never picked automatically
pygame.mixer.set_reserved(1)
...
# create your Sound and set the volume
music = pygame.mixer.Sound(...)
music.set_volume(0.5)
music.play()
# get a channel to play the sound
channel = pygame.mixer.find_channel(True) # should always find a channel
channel.play(music)

Music player for Python not working

I want to be able to play multiple songs through a playlist using python, but it will only play the last song on the list. Please help.
from pygame import mixer # Load the required library
from os import listdir
k = listdir('C:/LOCAL')
print(k)
mixer.init()
for x in k:
y = "C:/LOCAL/" + x
print y
mixer.music.queue(y)
mixer.music.load(y)
mixer.music.play()
Your problem is that you assume that playing music with pygame will pause the program until the music is finished - which is not the case. As a result, it tries starting a song, and then it's starting another, and another, etc.
There are a few ways of trying to correct this. You could either:
Use pygame events and "tell" pygame to fire an event when the song finishes (though this requires a display surface (window) to be opened within pygame), or
Detect the length of the song, and sleep for that amount of time (which is more compatible with your current code).
I'm going to assume that you would like to do option 2, since your code works better with it.
To get the length of an MP3 file (I've not tried it with any other types), you could use the Mutagen library.
Some example code to get the length of an MP3 file (in seconds):
from mutagen.mp3 import MP3
tracklength = MP3("/path/to/song.mp3").info.length
Then you could substitute the path with y, and time.sleep for the amount of time returned, before continuing to the next iteration of the loop.
Hope that helps.
(also, you don't need to queue a file before loading it - just load and play)

What is preventing the sound files from being played in this pygame Mixer set up?

I'm trying to write a small bit of code to play music files in the background of a game. The problem I'm coming across is that despite all the code being laid out and phrased properly no sound files will play. I put several print statements in the code and it seems to suggest that the sound file is either not loading or is simply not playing once it loads?
import pygame
def musicPlayer():
print "Playing music now"
pygame.init()
pygame.mixer.music.load('01ANightOfDizzySpells.mp3')
print "load song1"
pygame.mixer.music.play(loops=0, start=0.0)
print "play song1"
pygame.mixer.music.queue('01HHavok-intro.mp3')
pygame.mixer.music.queue('02HHavok-main.mp3')
pygame.mixer.music.queue('02Underclockedunderunderclockedmix.mp3')
pygame.mixer.music.queue('03ChibiNinja.mp3')
pygame.mixer.music.queue('04AllofUs.mp3')
pygame.mixer.music.queue('05ComeandFindMe.mp3')
pygame.mixer.music.queue('06Searching.mp3')
pygame.mixer.music.queue('07WeretheResistors.mp3')
pygame.mixer.music.queue('08Ascending.mp3')
pygame.mixer.music.queue('09ComeandFindMe-Bmix.mp3')
pygame.mixer.music.queue('10Arpanauts.mp3')
pygame.mixer.music.queue('DigitalNative.mp3')
pygame.mixer.music.set_endevent()
#musicPlayer()
musicPlayer()
Am I missing something basic? Or could it have to do with my computer not the code?
Edit: this is the output from running the code
Playing music now
load song1
play song1
As you can see it throws no errors.
I tried your code with a mid file, it works fine, but there's some adjustments:
import pygame
def musicPlayer():
pygame.init()
pygame.mixer.music.load('test.mid')
print "load song1"
pygame.mixer.music.play()
print "play song1"
pygame.mixer.music.queue('test_2.mid')
musicPlayer()
while pygame.mixer.music.get_busy():
pygame.time.Clock().tick(10)
print "DONE"
if the script ends the play won't happend, for that you need to get_busy() in a while loop.
in the documentation of pygame.music it states: Be aware that MP3 support is limited [...] Consider using OGG instead.
I played a little with the Sound class.
Here's what I came up:
import pygame
def musicPlayer():
pygame.mixer.init()
channel = pygame.mixer.Channel(1)
sound = pygame.mixer.Sound('test.ogg')
channel.play(sound)
musicPlayer()
while pygame.mixer.get_busy():
pygame.time.Clock().tick(10)
print "DONE"
I'm not very familiar with pygame and its methods, but my guess is that either it cannot find the file correctly, or it's not able to correctly handle the file that it finds.
I would suggest putting the full path to audio files to see if that helps. That would rule out the issue of it not finding the files properly (although hardcoding this is obviously not a good idea long-term as any changes you make to the organizational structure of your program will likely break those paths).
And according to their documentation, their MP3 support is limited. You might try using .ogg files instead (http://www.pygame.org/docs/ref/music.html) as it could just be an issue with the encoding not being fully supported.

Setting volume globally in pygame.Sound module

I have been trying to set volume to all the sound playing using pygame.
def on_press(self):
file_name = self.filename
pygame.mixer.pre_init(44100, 16, 2, 4096)
pygame.init()
pygame.mixer.init(44100)
channel=pygame.mixer.Sound(file_name)
channel.play(0)
every time I press a button in the front end, A sound plays. I can play as many sounds I can.
Now my question is how do I control volume of all the music? Here I should create object for each file and set its volume value. Code is below
channel=pygame.mixer.Sound(file_name)
channel.play(0)
How do I set the volume globally? All files that are playing should be affected with given volume?
Thanks for any help!
I believe you have to set each one individually with Sound.set_volume(value). You will have to store each Sound instance you create and then loop through them when you want the volume to change. If you want to set each one depending on the volume it was already, you can do something like:
def set_all_volume(sounds,mult):
for sound in sounds:
vol = sound.get_volume()
sound.set_volume(min(vol*mult,1.0))
I'm using a function for setting the volume globally. The function contains a sound.set.volume() line where you can set the volume for all sound objects created with that function.
# Audio
pygame.mixer.init()
# Sound
def create_sound04(name):
fullname = "audio/sound/" + name # path + name of the sound file
sound = pygame.mixer.Sound(fullname)
sound.set_volume(0.40)
return sound
With that function I create my sound objects.
closedGate = create_sound04("closedGate.wav")
openGate = create_sound04("openGate.wav")
They are all set to the same volume and ready to be played.
You can also create a second function with a different volume and/or different path using a different function name.

Stop Winsound / Stop a thread on Python

Im writing a litle game on python using Tkinter (And by the way, i am not allowed to use any other non built in modules) and I want to play a background song when on the main window, wich is the one that holds the title, and the buttons to go to other windows and stuff...
So the thing is that I need that sound to stop when I enter to another window, but when I hit the button to go, to another window, the song keeps playing...
I'm using the winsound module, and had define a couple of functions, (That by the way, are wicked as hell) to play the song when I first run the program using threads...
So here is the deal, I want something to put in the function "killsound" so that I can add it to every button, and then when I press any button to open any other window, the sound will be killed.
I was hoping something like 'a.kill()' or 'a.stop()' but it didnt worked.
And I really donĀ“t know how to use the SND_PURGE thing on winsound... Although I understand that SND_PURGE is no longer working on new windows OS (Got Win8.1)
Could you please help me?
Thank You! (And Sorry for the creepy english...)
def Play(nombre): #This function Is the core of the winsound function
ruta = os.path.join('Audio',nombre)
Reproducir= winsound.PlaySound(ruta,winsound.SND_FILENAME)
return Reproducir
def PlayThis():
while flag_play:
try:
return Play('prettiest weed.wav')
except:
return "Error"
def PlayThisThread():
global flag_play
flag_play= True
a=Thread(target=PlayThis, args=())
a.daemon = True
a.start()
PlayThisThread()
def killsound(): #This is the function I want, for killing sound.
global flag_play
flag_play = False
There are 2 major problems in your code:
global variable flag_play has to be placed inside the sound playback loop, in your case within the PlayThis() function
the Winsound module is aiming simple non-threaded usage. while the sound is playbacked, there is no chance to "softly" interrupt. It does not support any playback status reporting e.g. .isPlaying() nor any kind of .stop() that you need in order to kill it.
Solution:
try PyMedia package. Pymedia allows lower-level audio manipulation therefore more details have to be provided at the initialisation:
import time, wave, pymedia.audio.sound as sound
# little to do on the proper audio setup
f= wave.open( 'prettiest weed.wav', 'rb' )
sampleRate= f.getframerate() # reads framerate from the file
channels= f.getnchannels()
format= sound.AFMT_S16_LE # this sets the audio format to most common WAV with 16-bit codec PCM Linear Little Endian, use either pymedia or any external utils such as FFMPEG to check / corvert audio into a proper format.
audioBuffer = 300000 # you are able to control how much audio data is read
with the following assigment the "snd" becomes an instance of the class sound.Output and gives you bunch of useful audio methods:
snd= sound.Output( sampleRate, channels, format )
s= f.readframes( audioBuffer )
snd.play( s )
and finally your threaded playback loop might look as follows:
while snd.isPlaying():
global flag_play
if not flag_play: snd.stop() #here is where the playback gets interupted.
time.sleep( 0.05 )
f.close()
Please, let me know if you need more support on this.
I also created a 0.5 sec wavfile in Adobe Audition containing silence and attached it to the stop button, and this basically "stopped" playback of the previously played audio clip.
I found a way to do it, by adding a 0.5sec sound to a button, so that when I press the button it stops the background one to play the button one, and then stops all sounds on program.

Categories

Resources