Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pygame.Music #3110

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft

pygame.Music #3110

wants to merge 2 commits into from

Conversation

bilhox
Copy link
Contributor

@bilhox bilhox commented Sep 22, 2024

Hello everyone,

Proud to propose you a first version of the pygame.Music object after days of work.

Tasks not finished yet :

  • Reduce the need for SDL_Mixer +2.6.0 functions
  • Add macros so github tests can breath
  • Return -1.0 for unsupported formats (wav, midi ...) when getting the duration and other things
  • Add doc
  • Add tests
  • fadein and fadeout properties
  • playing property
  • MUSICENDED event when the music is stopped / ends.
    ... and many bugs hidden under the carpet to fix ...

Current test code (Use your own musics, who knows, there might be some issues):

import pygame

def main():
    pygame.init()
    music = pygame.Music("music1.mp3")
    music2 = pygame.Music("music2.mp3")

    musics = [music, music2]
    index = 0

    screen = pygame.display.set_mode([800, 800])
    font = pygame.Font(None)

    musics[index].play()

    clock = pygame.Clock()

    running = True

    while running:

        dt = clock.tick() / 1000
        screen.fill("white")

        text = f"""
        fps = {round(clock.get_fps(), 2)}fps

        Title : {musics[index].title}
        Artist : {musics[index].artist}
        Album : {musics[index].album}
        Copyright : {musics[index].copyright}

        music position = {round(musics[index].position, 2)}s
        music duration = {round(musics[index].duration, 2)}s
        music volume = {round(musics[index].volume * 100)}%
        music paused = {musics[index].paused}
        music ended = {musics[index].ended}
        """
        screen.blit(font.render(text, True, "black"))

        pygame.display.flip()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_s:
                    musics[index].stop()
                elif event.key == pygame.K_r:
                    musics[index].rewind()
                elif event.key == pygame.K_p:
                    musics[index].play(fade_in=3)
                elif event.key == pygame.K_a:
                    musics[index].position -= 5
                elif event.key == pygame.K_z:
                    musics[index].position += 5
                elif event.key == pygame.K_o:
                    musics[index].paused = not musics[index].paused
                
                if event.key == pygame.K_UP:
                    musics[index].volume += 0.05
                elif event.key == pygame.K_DOWN:
                    musics[index].volume -= 0.05
                elif event.key == pygame.K_LEFT:
                    index = (index - 1) % len(musics)
                elif event.key == pygame.K_RIGHT:
                    index = (index + 1) % len(musics)

            elif event.type == pygame.TEXTINPUT:
                try:
                    music_index = int(event.text)
                    index = pygame.math.clamp(music_index - 1, 0, 1)
                except:
                    continue

    pygame.quit()

if __name__ == "__main__":
    main()

@bilhox bilhox added mixer.music pygame.mixer.music New API This pull request may need extra debate as it adds a new class or function to pygame labels Sep 22, 2024
@bilhox bilhox linked an issue Sep 22, 2024 that may be closed by this pull request
@bilhox bilhox self-assigned this Sep 22, 2024
@@ -19,3 +19,34 @@ def queue(filename: FileLike, namehint: str = "", loops: int = 0) -> None: ...
def set_endevent(event_type: int, /) -> None: ...
def get_endevent() -> int: ...
def get_metadata(filename: Optional[FileLike] = None, namehint: str = "") -> Dict[str, str]: ...

class Music:
def __init__(self, filename: FileLike, namehint: Optional[str] = "") -> None: ...
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

namehint cannot be type None: it should be just str, not Optional[str].
In fact, the type annotation for pygame.mixer.music.load should be fixed in this way too because it also cannot take None.

@Starbuck5
Copy link
Member

So this is some syntactic sugar around the existing music system. And unlike pygame.Window it's not an OOP-ization of a system because we need to support multiple when before we only supported one, we'll still only support one playing at once.

If we add this I'd like it to be easy to maintain, so in that vein, why is this written in C?

@property
def duration(self) -> float: ...
@property
def paused(self) -> bool: ...
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing paused setter in stub.

@bilhox
Copy link
Contributor Author

bilhox commented Sep 23, 2024

So this is some syntactic sugar around the existing music system. And unlike pygame.Window it's not an OOP-ization of a system because we need to support multiple when before we only supported one, we'll still only support one playing at once.

If we add this I'd like it to be easy to maintain, so in that vein, why is this written in C?

For several reasons :

  • music pre-loading (it's not about performances, but for playing a music in just 2 lines)
  • fixes the position problem
  • Uses new mixer functions (You suggested to access this via python functions, I don't support idea)
  • Needs access to the music playing via Music obj or old system so only one music is set to playback.

@aatle
Copy link
Contributor

aatle commented Sep 24, 2024

Is there a specific reason why there is an ended property instead of a playing property, because I think playing would make much more sense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
mixer.music pygame.mixer.music New API This pull request may need extra debate as it adds a new class or function to pygame
Projects
None yet
Development

Successfully merging this pull request may close these issues.

pygame.music.Music implementation
3 participants