pygame编写音乐播放器的实现代码示例


Posted in Python onNovember 19, 2019

1、准备工作

ide:pycharm
python:3.7
三方包:pygame、pyinstaller、mutagen
几首mp3格式的歌

2、开始

2.1 设计说明

1、包含 上一首、下一首、暂停/播放、快进/快退、显示当前播放的歌曲名称、显示播放进度条
2、使用pygame.mixer
3、随机播放磁盘某个目录及其子目录下的mp3文件
4、上一首、下一首用随机选择choice(list) 实现
5、进度条用按照一定速度移动进度图片来实现,过程中处理暂停、快进
6、歌曲快进播放用pygame.mixer.music.play(0,d_song_time) 实现
7、暂停用pygame.mixer.music.pause() 实现
8、播放用pygame.mixer.music.unpause() 实现
9、用mutagen.mp3来获取mp3信息

2.2 代码逻辑

收集某个目录下的所有mp3

# 收集某个目录及子目录下的MP3格式的文件
# 返回歌曲路径、歌曲时长
# [['E:\\musics\\Mirror_Yohee_128K.mp3', 236], ['E:\\musics\\over here_Nobigdyl_128K.mp3', 188], ['E:\\musics\\尘_薛之谦_128K.mp3', 282], ['E:\\musics\\aaa\\尘_薛之谦_128K.mp3', 282]]
def collect_songs(fidir):
  musics =[]
  for root, dirs, files in os.walk(fidir):
    for file in files:
      tmp =[]
      if file.endswith('mp3'):
        file = os.path.join(root,file)
        song = MP3(file)
        duration = round(song.info.length)
        tmp.append(file)
        tmp.append(duration)
        musics.append(tmp)
  return musics

显示歌曲名称

# 把歌曲名字显示在播放器上
def draw_song_name(music):
  # 取歌曲名
  music_name = music[0].split("\\")[-1]
  # print(music_name)
  wbk_obj = font_obj.render(music_name, True, (0, 255, 255))
  k_obj = wbk_obj.get_rect()
  k_obj.center = (340, 200)
  screen.blit(wbk_obj, k_obj)
  pygame.display.update()

播放歌曲

# 随机播放一首歌
def sing_a_song(musics):
  # 随机选择一首音乐
  music = choice(musics)
  print(type(musics))
  pygame.mixer.music.load(music[0])
  pygame.mixer.music.play()
  print('开始播放:%s -- %s秒'%(music[0] , str(music[1])))
  return music

显示播放进度

# 播放进度显示
def move(current_time,start_time,pause_duration_time,c_music):
  if pause_end_time == 0 and pause_start_time != 0:
    duration_time = round(pause_start_time - start_time - pause_duration_time)
  else:
    duration_time = round(current_time - start_time - pause_duration_time)
  song_total_time = c_music[1]
  speed = (end_x-begin_x)/song_total_time
  current_x = begin_x + duration_time*speed
  try:
    screen.blit(dian,(current_x,148))
    pygame.display.update()
  except:
    print(current_time)
    print(start_time)
    print(pause_duration_time)
    exit()

快进快退功能

# 快进快退功能
def kuaijin(jindu_x,c_music):
  # 要跳转到的距离d_x
  d_x = jindu_x - begin_x
  song_total_time = c_music[1]
  # 要跳转到的时间d_song_time
  d_song_time = round(song_total_time*(d_x/560),1)
  # 将歌曲快进到d_song_time
  pygame.mixer.music.play(0,d_song_time)

画播放控件

# 画播放控件
def draw_kongjian(is_sing,is_pause):
  # 画进度条
  # 画一条宽度为2的线,y高度为149,x从40到600,颜色为(0,100,100)
  pygame.draw.line(screen, (0, 100, 100), (40, 149), (600, 149), 2)
  # 画播放、暂停按钮
  # 先画圆边框,半径20
  pygame.draw.circle(screen, (0, 255, 255), (x + 80, 100), 20, 2)
  # 画三角形,开始播放
  pygame.draw.line(screen, (0, 255, 255), (x + 73.7, 107.5), (x + 73.7, 93), 2) # 竖线
  # 如果正在播放且没有暂停
  if is_sing and not is_pause:
    # 隐藏三角形
    pygame.draw.line(screen, (0, 89, 115), (x + 73.7, 107.5), (x + 87.3, 100), 2)
    pygame.draw.line(screen, (0, 89, 115), (x + 73.7, 93), (x + 87.3, 100), 2)
    # 显示第二条竖线
    pygame.draw.line(screen,(0,255,255),(x+83.7,107.5),(x+83.7,93),2)
  else:
    # 隐藏第二条竖线
    pygame.draw.line(screen, (0, 89, 115), (x + 83.7, 107.5), (x + 83.7, 93), 2)
    # 显示三角形
    pygame.draw.line(screen,(0,255,255),(x+73.7,107.5),(x+87.3,100),2)
    pygame.draw.line(screen,(0,255,255),(x+73.7,93),(x+87.3,100),2)

  # 画上一首按钮
  pygame.draw.line(screen, (0, 255, 255), (x - 10, 110), (x - 10, 90), 2)
  pygame.draw.line(screen, (0, 255, 255), (x - 10, 100), (x + 10, 115), 2)
  pygame.draw.line(screen, (0, 255, 255), (x - 10, 100), (x + 10, 85), 2)
  pygame.draw.line(screen, (0, 255, 255), (x + 10, 115), (x + 10, 85), 2)

  # 画下一首按钮
  pygame.draw.line(screen, (0, 255, 255), (x + 170, 110), (x + 170, 90), 2)
  pygame.draw.line(screen, (0, 255, 255), (x + 170, 100), (x + 150, 115), 2)
  pygame.draw.line(screen, (0, 255, 255), (x + 170, 100), (x + 150, 85), 2)
  pygame.draw.line(screen, (0, 255, 255), (x + 150, 115), (x + 150, 85), 2)

主逻辑

1、画界面
2、如果没有在播放音乐,播放之
3、如果正在播放音乐,刷新播放进度
4、点击了上一首的处理
5、点击了暂停/播放的处理
6、点击了下一首的处理
7、快进/快退的处理

while True:
  # 第一步画背景
  screen.fill((0, 0, 0)) # ----------------新添加
  # 第二步添加背景图片
  bg = pygame.image.load(music_bg)
  screen.blit(bg, (0, 0))
  # 第四步,画控件
  draw_kongjian(is_sing,is_pause)

  # print("status:-------" + str(pygame.mixer.music.get_busy()))
  # 如果正在播放音乐,有bug == 当暂停后返回依旧是1
  if pygame.mixer.music.get_busy() == 1:
    is_sing = True
  else:
    is_sing = False

  # 如果没有在播放音乐
  if not is_sing:
    # 第五步,开始唱歌
    c_music = sing_a_song(musics)
    # 记录开始播放时间
    start_time = time.time()
    # 暂停时长置为0
    pause_start_time = pause_end_time = pause_duration_time = 0
    # 进度条开始位置重置为40
    begin_x = 40
    # 第六步,显示歌名
    draw_song_name(c_music)
    # 更改播放状态
    is_sing = not is_sing
  # 如果正在唱歌
  else:
    # 第六步,显示歌名
    draw_song_name(c_music)
    current_time = time.time()
    move(current_time, start_time, pause_duration_time, c_music)


  for event in pygame.event.get():
    if event.type == QUIT:
      pygame.quit()
      exit()
    if event.type == MOUSEBUTTONDOWN:
      # 如果点击了鼠标左键,取到当前鼠标的坐标
      pressed_array = pygame.mouse.get_pressed()
      if pressed_array[0] == 1:
        mouse_x, mouse_y = event.pos
        print('点击了左键,位置为(%d,%d)'%(mouse_x,mouse_y))
        # 判断点击了哪个按钮
        if 80 < mouse_y < 120:
          if x - 5 < mouse_x < x + 15:
            # 点击了上一首
            c_music = sing_a_song(musics)
            is_pause = False
            is_kuaijin = False
            # 记录开始时间
            start_time = time.time()
            # 暂停时长置为0
            pause_start_time = pause_end_time = pause_duration_time = 0
            # 进度条开始位置置为40
            begin_x = 40
            # 第六步,显示歌名
            draw_song_name(c_music)
            print('点击了上一首')
          elif x+60 < mouse_x < x+100:
            # 修改是否暂停的状态
            is_pause = not is_pause
            # 如果没有暂停
            if not is_pause:
              # 开始播放
              pygame.mixer.music.unpause()
              # 记录结束暂定时间
              pause_end_time = time.time()
              # 计算暂停时长
              pause_duration_time = pause_duration_time + pause_end_time - pause_start_time
              # 暂停结束,暂停结束开始时间均置为0
              pause_end_time = pause_start_time = 0
            # 如果暂停了
            else:
              # 暂停播放
              pygame.mixer.music.pause()
              # 记录开始暂定时间
              pause_start_time = time.time()

            print('点击了暂停')
          elif x+145 < mouse_x < x+170:
            # 点击了下一首
            c_music = sing_a_song(musics)
            is_pause = False
            is_kuaijin = False
            # 记录开始时间
            start_time = time.time()
            # 暂停时长置为0
            pause_start_time = pause_end_time = pause_duration_time =0
            # 进度条开始位置置为40
            begin_x = 40
            # 第六步,显示歌名
            draw_song_name(c_music)
            print('点击了下一首')
        # 如果点了进度条的某个位置
        elif 155> mouse_y >145:
          kuaijin(mouse_x,c_music)
          begin_x = mouse_x
          pause_end_time = pause_start_time = pause_duration_time = 0
          move(current_time,start_time,pause_duration_time,c_music)
          is_kuaijin = True
          print("快进")

    pygame.display.update()

 3、效果图

pygame编写音乐播放器的实现代码示例

刺猬牛逼!!!

4、完整代码

#-*- coding: utf-8 -*-
import os,time,sys
from sys import exit
import pygame
from pygame.locals import *
from mutagen.mp3 import MP3
from random import choice


def rp(relative_path):
  """ Get absolute path to resource, works for dev and for PyInstaller """
  try:
    # PyInstaller creates a temp folder and stores path in _MEIPASS
    base_path = sys._MEIPASS
  except Exception:
    base_path = os.path.abspath(".")

  return os.path.join(base_path, relative_path)

pygame.init()
screen = pygame.display.set_mode((640, 480), 0, 32)
pygame.display.set_caption("music")
# 初始化音乐播放器
pygame.mixer.init()
# 背景图片
music_bg = rp(os.path.join('src','music_bg.jpg'))
# 进度点图片
dian_filename = rp(os.path.join('src','dian.jpg'))
dian = pygame.image.load(dian_filename)
# 字体
font_obj = pygame.font.Font('C:\Windows\Fonts\simsun.ttc',20)
# 偏移量基础值
x = 80
# 进度条开始x坐标
begin_x = 40
# 进度条结束x坐标
end_x = 600
# 是否正在播放歌曲,默认未播放
is_sing = False
# 是否暂停,默认未暂停
is_pause = False
# 是否快进了
is_kuaijin = False
# 快进后x坐标
jindu_x = -1
# 定义当前歌曲变量
global c_music
# 定义歌曲开始播放时间、当前时间、开始暂停时间、结束暂停时间
global start_time, current_time, pause_start_time, pause_end_time,pause_duration_time
pause_start_time =0
pause_end_time =0
pause_duration_time =0




# 把歌曲名字显示在播放器上
def draw_song_name(music):
  # 取歌曲名
  music_name = music[0].split("\\")[-1]
  # print(music_name)
  wbk_obj = font_obj.render(music_name, True, (0, 255, 255))
  k_obj = wbk_obj.get_rect()
  k_obj.center = (340, 200)
  screen.blit(wbk_obj, k_obj)
  pygame.display.update()


# 收集某个目录及子目录下的MP3格式的文件
# 返回歌曲路径、歌曲时长
# [['E:\\musics\\Mirror_Yohee_128K.mp3', 236], ['E:\\musics\\over here_Nobigdyl_128K.mp3', 188], ['E:\\musics\\尘_薛之谦_128K.mp3', 282], ['E:\\musics\\aaa\\尘_薛之谦_128K.mp3', 282]]
def collect_songs(fidir):
  musics =[]
  for root, dirs, files in os.walk(fidir):
    for file in files:
      tmp =[]
      if file.endswith('mp3'):
        file = os.path.join(root,file)
        song = MP3(file)
        duration = round(song.info.length)
        tmp.append(file)
        tmp.append(duration)
        musics.append(tmp)
  return musics

musics = collect_songs('E:\\musics')
print(musics)

# 随机播放一首歌
def sing_a_song(musics):
  # 随机选择一首音乐
  music = choice(musics)
  print(type(musics))
  pygame.mixer.music.load(music[0])
  pygame.mixer.music.play()
  print('开始播放:%s -- %s秒'%(music[0] , str(music[1])))
  return music


# 画代表当前进度的圆点
# 画一个直径为5个圆点,放在100,150的位置,颜色为(0,255,255)
# dian = pygame.draw.circle(screen,(0,255,255),(begin_x,150),6)


# 画播放控件
def draw_kongjian(is_sing,is_pause):
  # 画进度条
  # 画一条宽度为2的线,y高度为149,x从40到600,颜色为(0,100,100)
  pygame.draw.line(screen, (0, 100, 100), (40, 149), (600, 149), 2)
  # 画播放、暂停按钮
  # 先画圆边框,半径20
  pygame.draw.circle(screen, (0, 255, 255), (x + 80, 100), 20, 2)
  # 画三角形,开始播放
  pygame.draw.line(screen, (0, 255, 255), (x + 73.7, 107.5), (x + 73.7, 93), 2) # 竖线
  # 如果正在播放且没有暂停
  if is_sing and not is_pause:
    # 隐藏三角形
    pygame.draw.line(screen, (0, 89, 115), (x + 73.7, 107.5), (x + 87.3, 100), 2)
    pygame.draw.line(screen, (0, 89, 115), (x + 73.7, 93), (x + 87.3, 100), 2)
    # 显示第二条竖线
    pygame.draw.line(screen,(0,255,255),(x+83.7,107.5),(x+83.7,93),2)
  else:
    # 隐藏第二条竖线
    pygame.draw.line(screen, (0, 89, 115), (x + 83.7, 107.5), (x + 83.7, 93), 2)
    # 显示三角形
    pygame.draw.line(screen,(0,255,255),(x+73.7,107.5),(x+87.3,100),2)
    pygame.draw.line(screen,(0,255,255),(x+73.7,93),(x+87.3,100),2)

  # 画上一首按钮
  pygame.draw.line(screen, (0, 255, 255), (x - 10, 110), (x - 10, 90), 2)
  pygame.draw.line(screen, (0, 255, 255), (x - 10, 100), (x + 10, 115), 2)
  pygame.draw.line(screen, (0, 255, 255), (x - 10, 100), (x + 10, 85), 2)
  pygame.draw.line(screen, (0, 255, 255), (x + 10, 115), (x + 10, 85), 2)

  # 画下一首按钮
  pygame.draw.line(screen, (0, 255, 255), (x + 170, 110), (x + 170, 90), 2)
  pygame.draw.line(screen, (0, 255, 255), (x + 170, 100), (x + 150, 115), 2)
  pygame.draw.line(screen, (0, 255, 255), (x + 170, 100), (x + 150, 85), 2)
  pygame.draw.line(screen, (0, 255, 255), (x + 150, 115), (x + 150, 85), 2)

# 播放进度显示
def move(current_time,start_time,pause_duration_time,c_music):
  if pause_end_time == 0 and pause_start_time != 0:
    duration_time = round(pause_start_time - start_time - pause_duration_time)
  else:
    duration_time = round(current_time - start_time - pause_duration_time)
  song_total_time = c_music[1]
  speed = (end_x-begin_x)/song_total_time
  current_x = begin_x + duration_time*speed
  try:
    screen.blit(dian,(current_x,148))
    pygame.display.update()
  except:
    print(current_time)
    print(start_time)
    print(pause_duration_time)
    exit()

# 快进快退功能
def kuaijin(jindu_x,c_music):
  # 要跳转到的距离d_x
  d_x = jindu_x - begin_x
  song_total_time = c_music[1]
  # 要跳转到的时间d_song_time
  d_song_time = round(song_total_time*(d_x/560),1)
  # 将歌曲快进到d_song_time
  pygame.mixer.music.play(0,d_song_time)




while True:
  # 第一步画背景
  screen.fill((0, 0, 0)) # ----------------新添加
  # 第二步添加背景图片
  bg = pygame.image.load(music_bg)
  screen.blit(bg, (0, 0))
  # 第四步,画控件
  draw_kongjian(is_sing,is_pause)

  # print("status:-------" + str(pygame.mixer.music.get_busy()))
  # 如果正在播放音乐,有bug == 当暂停后返回依旧是1
  if pygame.mixer.music.get_busy() == 1:
    is_sing = True
  else:
    is_sing = False

  # 如果没有在播放音乐
  if not is_sing:
    # 第五步,开始唱歌
    c_music = sing_a_song(musics)
    # 记录开始播放时间
    start_time = time.time()
    # 暂停时长置为0
    pause_start_time = pause_end_time = pause_duration_time = 0
    # 进度条开始位置重置为40
    begin_x = 40
    # 第六步,显示歌名
    draw_song_name(c_music)
    # 更改播放状态
    is_sing = not is_sing
  # 如果正在唱歌
  else:
    # 第六步,显示歌名
    draw_song_name(c_music)
    current_time = time.time()
    move(current_time, start_time, pause_duration_time, c_music)


  for event in pygame.event.get():
    if event.type == QUIT:
      pygame.quit()
      exit()
    if event.type == MOUSEBUTTONDOWN:
      # 如果点击了鼠标左键,取到当前鼠标的坐标
      pressed_array = pygame.mouse.get_pressed()
      if pressed_array[0] == 1:
        mouse_x, mouse_y = event.pos
        print('点击了左键,位置为(%d,%d)'%(mouse_x,mouse_y))
        # 判断点击了哪个按钮
        if 80 < mouse_y < 120:
          if x - 5 < mouse_x < x + 15:
            # 点击了上一首
            c_music = sing_a_song(musics)
            is_pause = False
            is_kuaijin = False
            # 记录开始时间
            start_time = time.time()
            # 暂停时长置为0
            pause_start_time = pause_end_time = pause_duration_time = 0
            # 进度条开始位置置为40
            begin_x = 40
            # 第六步,显示歌名
            draw_song_name(c_music)
            print('点击了上一首')
          elif x+60 < mouse_x < x+100:
            # 修改是否暂停的状态
            is_pause = not is_pause
            # 如果没有暂停
            if not is_pause:
              # 开始播放
              pygame.mixer.music.unpause()
              # 记录结束暂定时间
              pause_end_time = time.time()
              # 计算暂停时长
              pause_duration_time = pause_duration_time + pause_end_time - pause_start_time
              # 暂停结束,暂停结束开始时间均置为0
              pause_end_time = pause_start_time = 0
            # 如果暂停了
            else:
              # 暂停播放
              pygame.mixer.music.pause()
              # 记录开始暂定时间
              pause_start_time = time.time()

            print('点击了暂停')
          elif x+145 < mouse_x < x+170:
            # 点击了下一首
            c_music = sing_a_song(musics)
            is_pause = False
            is_kuaijin = False
            # 记录开始时间
            start_time = time.time()
            # 暂停时长置为0
            pause_start_time = pause_end_time = pause_duration_time =0
            # 进度条开始位置置为40
            begin_x = 40
            # 第六步,显示歌名
            draw_song_name(c_music)
            print('点击了下一首')
        # 如果点了进度条的某个位置
        elif 155> mouse_y >145:
          kuaijin(mouse_x,c_music)
          begin_x = mouse_x
          pause_end_time = pause_start_time = pause_duration_time = 0
          move(current_time,start_time,pause_duration_time,c_music)
          is_kuaijin = True
          print("快进")

    pygame.display.update()

5、打包为exe

请查看另一篇文章

pyinstaller打包exe踩过的坑

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python中的闭包总结
Sep 18 Python
python实现的用于搜索文件并进行内容替换的类实例
Jun 28 Python
Python3字符串学习教程
Aug 20 Python
Python脚本实现自动发带图的微博
Apr 27 Python
python实现xlsx文件分析详解
Jan 02 Python
python生成密码字典的方法
Jul 06 Python
解决tensorflow1.x版本加载saver.restore目录报错的问题
Jul 26 Python
Python并发之多进程的方法实例代码
Aug 15 Python
python之PyQt按钮右键菜单功能的实现代码
Aug 17 Python
详解pyinstaller生成exe的闪退问题解决方案
Jun 19 Python
Python应用自动化部署工具Fabric原理及使用解析
Nov 30 Python
selenium学习教程之定位以及切换frame(iframe)
Jan 04 Python
pyinstaller打包程序exe踩过的坑
Nov 19 #Python
基于Python中的yield表达式介绍
Nov 19 #Python
Python函数式编程指南:对生成器全面讲解
Nov 19 #Python
wxPython电子表格功能wx.grid实例教程
Nov 19 #Python
python 实现return返回多个值
Nov 19 #Python
wxPython实现带颜色的进度条
Nov 19 #Python
Python使用Pandas读写Excel实例解析
Nov 19 #Python
You might like
php读取der格式证书乱码解决方法
2015/06/22 PHP
jquery 操作单选框,复选框,下拉列表实现代码
2009/10/27 Javascript
JavaScript 组件之旅(一)分析和设计
2009/10/28 Javascript
让IE8支持DOM 2(不用框架!)
2009/12/31 Javascript
Jquery调用webService远程访问出错的解决方法
2010/05/21 Javascript
jQuery总体架构的理解分析
2011/03/07 Javascript
JavaScript高级程序设计 阅读笔记(十二) js内置对象Math
2012/08/14 Javascript
jQuery检测返回值的数据类型
2015/07/13 Javascript
jQuery实现的跨容器无缝拖动效果代码
2016/06/21 Javascript
在网页中插入百度地图的步骤详解
2016/12/02 Javascript
js实现首屏延迟加载实现方法 js实现多屏单张图片延迟加载效果
2017/07/17 Javascript
vue.js移动端app之上拉加载以及下拉刷新实战
2017/09/11 Javascript
微信小程序返回多级页面的实现方法
2017/10/27 Javascript
jQuery中内容过滤器简单用法示例
2018/03/31 jQuery
Layui 设置select下拉框自动选中某项的方法
2018/08/14 Javascript
简单了解JavaScript中常见的反模式
2019/06/21 Javascript
Python中使用items()方法返回字典元素对的教程
2015/05/21 Python
python数据结构之图的实现方法
2015/07/08 Python
python基于itchat实现微信群消息同步机器人
2017/02/27 Python
Python中的 ansible 动态Inventory 脚本
2020/01/19 Python
Tensorflow 实现将图像与标签数据转化为tfRecord文件
2020/02/17 Python
python基于win32api实现键盘输入
2020/12/09 Python
1688平价精选商城:阿里集团旗下,工厂出厂价格直销
2017/04/24 全球购物
意大利网上购书网站:Libraccio.it
2021/02/03 全球购物
如何在Shell脚本中使用函数
2015/09/06 面试题
技校教师求职简历的自我评价
2013/10/20 职场文书
竞选演讲稿范文
2013/12/28 职场文书
三年级语文教学反思
2014/02/01 职场文书
《菜园里》教学反思
2014/04/17 职场文书
竞选班干部演讲稿600字
2014/08/20 职场文书
党员学习正风肃纪思想汇报
2014/09/12 职场文书
先进工作者事迹材料
2014/12/23 职场文书
蓬莱阁导游词
2015/02/04 职场文书
元旦主持词开场白
2015/05/29 职场文书
2016继续教育研修日志
2015/11/13 职场文书
Python基础之变量的相关知识总结
2021/06/23 Python