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 相关文章推荐
Linux中安装Python的交互式解释器IPython的教程
Jun 13 Python
python入门前的第一课 python怎样入门
Mar 06 Python
Python实现的多进程和多线程功能示例
May 29 Python
Python实现图片转字符画的代码实例
Feb 22 Python
scrapy-redis的安装部署步骤讲解
Feb 27 Python
python 返回一个列表中第二大的数方法
Jul 09 Python
python实现在多维数组中挑选符合条件的全部元素
Nov 26 Python
Python django框架开发发布会签到系统(web开发)
Feb 12 Python
keras 如何保存最佳的训练模型
May 25 Python
Python devel安装失败问题解决方案
Jun 09 Python
Python中实现一行拆多行和多行并一行的示例代码
Sep 06 Python
Python全局变量与global关键字常见错误解决方案
Oct 05 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输出控制功能在简繁体转换中的应用
2006/10/09 PHP
PHPStrom中实用的功能和快捷键大全
2015/09/23 PHP
利用php做服务器和web前端的界面进行交互
2016/10/31 PHP
Yii 2.0实现联表查询加搜索分页的方法示例
2017/08/02 PHP
javascript实现上传图片并预览的效果实现代码
2011/04/11 Javascript
JavaScript对象和字串之间的转换实例探讨
2013/04/21 Javascript
JS页面延迟执行一些方法(整理)
2013/11/11 Javascript
JS模式之简单的订阅者和发布者模式完整实例
2015/06/30 Javascript
JavaScript的Polymer框架中dom-repeat与VM的相关操作
2015/07/29 Javascript
JQuery 在文档中查找指定name的元素并移除的实现方法
2016/05/19 Javascript
jquery Ajax 全局调用封装实例详解
2017/01/16 Javascript
jQuery EasyUI之验证框validatebox实例详解
2017/04/10 jQuery
微信小程序实现YDUI的ScrollTab组件
2018/02/02 Javascript
javascript写一个ajax自动拦截并下载数据代码实例
2019/09/07 Javascript
Python中for循环和while循环的基本使用方法
2015/08/21 Python
python使用selenium实现批量文件下载
2019/03/11 Python
Falsk 与 Django 过滤器的使用与区别详解
2019/06/04 Python
Python Selenium 之数据驱动测试的实现
2019/08/01 Python
numpy.random.shuffle打乱顺序函数的实现
2019/09/10 Python
Python帮你微信头像任意添加装饰别再@微信官方了
2019/09/25 Python
浅谈在django中使用filter()(即对QuerySet操作)时踩的坑
2020/03/31 Python
详解Ubuntu环境下部署Django+uwsgi+nginx总结
2020/04/02 Python
Numpy 理解ndarray对象的示例代码
2020/04/03 Python
Python多线程实现支付模拟请求过程解析
2020/04/21 Python
Python正则表达式高级使用方法汇总
2020/06/18 Python
寻找迷宫的一条出路,o通路;X:障碍
2016/07/10 面试题
数学专业毕业生自荐信
2013/11/10 职场文书
信息系统专业个人求职信范文
2013/12/07 职场文书
采购部主管岗位职责
2014/01/01 职场文书
英语专业学生个人求职信范文
2014/01/06 职场文书
平面设计求职信
2014/03/10 职场文书
文体活动实施方案
2014/03/27 职场文书
新教师个人工作总结
2015/02/06 职场文书
小学生反邪教心得体会
2016/01/15 职场文书
Ajax是什么?Ajax高级用法之Axios技术
2021/04/21 Javascript
Javascript的promise,async和await的区别详解
2022/03/24 Javascript