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 29 Python
Python实现统计给定列表中指定数字出现次数的方法
Apr 11 Python
解决python nohup linux 后台运行输出的问题
May 11 Python
Python 脚本获取ES 存储容量的实例
Dec 27 Python
使用PyQtGraph绘制精美的股票行情K线图的示例代码
Mar 14 Python
pandas DataFrame 交集并集补集的实现
Jun 24 Python
python实现关闭第三方窗口的方法
Jun 28 Python
一行python实现树形结构的方法
Aug 09 Python
在tensorflow中实现屏蔽输出的log信息
Feb 04 Python
Python控制台实现交互式环境执行
Jun 09 Python
Python语言编写智力问答小游戏功能
Oct 13 Python
如何使用Pytorch搭建模型
Oct 26 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
实现“上一页”和“下一页按钮
2006/10/09 PHP
Zend Guard一些常见问题解答
2008/09/11 PHP
iframe自适应宽度、高度 ie6 7 8,firefox 3.86下测试通过
2010/07/29 Javascript
jsp js鼠标移动到指定区域显示选项卡离开时隐藏示例
2013/06/14 Javascript
jquery插件lazyload.js延迟加载图片的使用方法
2014/02/19 Javascript
JavaScript中的this关键字使用详解
2015/08/14 Javascript
JavaScript截取、切割字符串的技巧
2016/01/07 Javascript
强大的 Angular 表单验证功能详细介绍
2017/05/23 Javascript
解决vue2.x中数据渲染以及vuex缓存的问题
2017/07/13 Javascript
BootStrap Fileinput插件和Bootstrap table表格插件相结合实现文件上传、预览、提交的导入Excel数据操作步骤
2017/08/07 Javascript
Vue from-validate 表单验证的示例代码
2017/09/26 Javascript
JavaScript实现短暂提示框功能
2018/04/04 Javascript
vue监听input标签的value值方法
2018/08/27 Javascript
微信小程序一周时间表功能实现
2019/10/17 Javascript
在JavaScript中实现链式调用的实现
2019/12/24 Javascript
Vue axios获取token临时令牌封装案例
2020/09/11 Javascript
vue 函数调用加括号与不加括号的区别
2020/10/29 Javascript
[46:14]完美世界DOTA2联赛PWL S3 Magma vs INK ICE 第一场 12.11
2020/12/16 DOTA
python基于windows平台锁定键盘输入的方法
2015/03/05 Python
介绍Python的Django框架中的QuerySets
2015/04/20 Python
Python 常用 PEP8 编码规范详解
2017/01/22 Python
多版本Python共存的配置方法
2017/05/22 Python
详解appium+python 启动一个app步骤
2017/12/20 Python
Python 占位符的使用方法详解
2019/07/10 Python
python 使用raw socket进行TCP SYN扫描实例
2020/05/05 Python
python eventlet绿化和patch原理
2020/11/21 Python
用HTML5制作一个简单的桌球游戏的教程
2015/05/12 HTML / CSS
JustFab加拿大:女鞋、靴子、手袋和服装在线
2018/05/18 全球购物
Andrew Marc官网:设计师外套的领先制造商
2019/10/30 全球购物
护理专业推荐信
2013/11/07 职场文书
中专生求职自荐信范文
2013/12/22 职场文书
会计电算化大学生职业规划书
2014/02/05 职场文书
关于孝道的演讲稿
2014/05/21 职场文书
大学生党员个人总结
2015/02/13 职场文书
合作协议书格式范本
2016/03/21 职场文书
如何用Laravel包含你自己的帮助函数
2021/05/27 PHP