master
王新宇 3 years ago
commit 85bd7399e5

@ -0,0 +1,336 @@
import wx
import urllib.request
import pygame
import os
import re
import time
from threading import Thread
import math
import datetime
APP_TITLE = u'音乐播放器'
MAX_LYRIC_ROW = 15
LYRIC_ROW_REG = '\[[0-9]{2}:[0-9]{2}.[0-9]{2,}\]'
MAX_MUSIC_NAME_LEN = 18
class mainFrame(wx.Frame):
'''程序主窗口类继承自wx.Frame'''
def __init__(self):
'''构造函数'''
# 播放器的整体属性
self.width = 1280
self.height = 720
self.volume = 0
self.local_music_folder = "music_folder"
wx.Frame.__init__(self, None, -1, APP_TITLE)
self.SetSize(self.width, self.height)
self.SetBackgroundColour((200,200,200)) # 设置界面的背景颜色
# 音乐列表有关
self.local_music_name_list = [] # 当前音乐名字列表
self.lyrcis_static_text = [] # 当前播放的音乐的歌词列表
self.play_stop_button = None # 播放、暂停按钮
self.current_music_state = 0 # 是否有音乐在播放0表示否
self.current_music_index = 0 # 当前音乐的索引
# 初始化本地歌曲列表
self.get_local_music_list()
self.current_music_static_text = None # 当前播放的音乐的名字
# 按钮使用的图片
self.play_bmp = wx.Image("resource/播放.png", wx.BITMAP_TYPE_PNG).Rescale(30, 30).ConvertToBitmap()
self.stop_bmp = wx.Image("resource/暂停.png", wx.BITMAP_TYPE_PNG).Rescale(30, 30).ConvertToBitmap()
# 导航栏所在的panel
self.navi_panel = None
self.draw_navi_panel()
# 歌曲列表所在的panel
self.music_list_panel = None
self.draw_music_list_panel()
# 播放部分所在的panel
self.play_music_panel = None
self.draw_play_music_panel()
# 歌词部分所在的panel
self.music_lyric_panel = None
self.draw_music_lyric_panel()
# 下载音乐面板
self.down_music_panel = None
self.input_url_text_ctrl = None # 输入的下载路径
self.down_button = None # 下载按钮
self.draw_down_music_panel()
pygame.mixer.init()
self.music = pygame.mixer.music
self.SONG_FINISHED = pygame.USEREVENT + 1
def get_path_by_name(self, file_name):
return os.path.join(self.local_music_folder, file_name)
def get_local_music_list(self):
self.local_music_name_list.clear() # 这一步必须有
for local_music_file_name in os.listdir(self.local_music_folder):
if local_music_file_name.endswith(".mp3"):
self.local_music_name_list.append(local_music_file_name)
def draw_navi_panel(self):
# 导航栏所在的panel
self.navi_panel = wx.Panel(self, id=-1, pos=(0, 0), size=(100, self.height - 100))
# 本地音乐
local_music_text = wx.StaticText(self.navi_panel, -1, "本地音乐", pos=(20, 20), style=wx.ALIGN_LEFT)
local_music_text.SetOwnForegroundColour((0, 0, 0))
def draw_music_list_panel(self):
# 重新计算本地音乐列表
self.get_local_music_list()
# 绘制面板整体
if self.music_list_panel is not None:
self.music_list_panel.Destroy()
self.music_list_panel = wx.Panel(self, id=-1, pos=(100, 0), size=(300, self.height - 100))
# 音乐列表
local_music_num = len(self.local_music_name_list)
for music_index in range(local_music_num):
music_full_name = self.local_music_name_list[music_index].replace(".mp3", "")
if len(music_full_name) > MAX_MUSIC_NAME_LEN:
music_full_name = music_full_name[0:MAX_MUSIC_NAME_LEN] + "..."
music_text = wx.StaticText(self.music_list_panel, -1, music_full_name,
pos=(0, music_index * 40 + 20), size=(270, 30), style=wx.ALIGN_RIGHT)
music_text.SetOwnForegroundColour((0,0,0))
music_text.Refresh() # 这句话不能少
play_button = wx.BitmapButton(self.music_list_panel, -1, self.play_bmp, pos=(280, music_index * 40 + 20),
size=(20, 20))
play_button.Bind(wx.EVT_LEFT_DOWN, lambda e, index=music_index: self.play_index_music(index))
def draw_play_music_panel(self):
# 播放音乐所在的panel
self.play_music_panel = wx.Panel(self, id=-1, pos=(0, self.height - 100), size=(self.width, 100))
# 歌的名字
self.current_music_static_text = wx.StaticText(self.play_music_panel, -1, "请选择歌曲",
pos=(100, 15), size=(200, 30), style=wx.ALIGN_RIGHT)
self.current_music_static_text.SetOwnForegroundColour((0,0,0))
last_music_bpm = wx.Image("resource/上一首.png", wx.BITMAP_TYPE_PNG).Rescale(30, 30).ConvertToBitmap()
next_music_bpm = wx.Image("resource/下一首.png", wx.BITMAP_TYPE_PNG).Rescale(30, 30).ConvertToBitmap()
last_music_button = wx.BitmapButton(self.play_music_panel, -1, last_music_bpm, pos=(340, 15), size=(30, 30))
self.play_stop_button = wx.BitmapButton(self.play_music_panel, -1, self.play_bmp, pos=(380, 15), size=(30, 30))
next_music_button = wx.BitmapButton(self.play_music_panel, -1, next_music_bpm, pos=(420, 15), size=(30, 30))
# 调节音量的按钮
volume_slider = wx.Slider(self.play_music_panel, -1, 50, 0, 100, pos=(500, 15), size=(570, -1), style=wx.SL_HORIZONTAL)
# 上述按钮的监听器
last_music_button.Bind(wx.EVT_LEFT_DOWN, self.play_last_music)
self.play_stop_button.Bind(wx.EVT_LEFT_DOWN, self.play_stop_music)
next_music_button.Bind(wx.EVT_LEFT_DOWN, self.play_next_music)
volume_slider.Bind(wx.EVT_SLIDER, self.change_volume)
def draw_down_music_panel(self):
'''
下载音乐所在的面板
:return:
'''
self.down_music_panel = wx.Panel(self, id=-1, pos=(400, 0), size=(self.width - 400, 60))
# 下载地址输入框
self.input_url_text_ctrl = wx.TextCtrl(self.down_music_panel, -1, "请输入下载链接", pos=(100, 20), size=(600, 30))
#self.input_url_text_ctrl.SetOwnBackgroundColour((63, 63, 63))
# 绘制下载图标
down_bmp = wx.Image("resource/下载.png", wx.BITMAP_TYPE_PNG).Rescale(30, 30).ConvertToBitmap()
self.down_button = wx.BitmapButton(self.down_music_panel, -1, down_bmp, pos=(700, 20), size=(30, 30))
# 监听下载图标按钮的鼠标点击事件
self.down_button.Bind(wx.EVT_LEFT_DOWN, self.download_music)
def play_music(self):
'''
重新载入播放音乐
:return:
'''
current_music_path = self.get_path_by_name(self.local_music_name_list[self.current_music_index])
self.music.load(current_music_path)
pygame.mixer.init()#pygame模块初始化
my_music = pygame.mixer.music
playing_time =my_music.get_pos()
print(playing_time)
# step1播放音乐
self.music.play(loops=1, start=0.0)
# 更改当前播放的音乐的名字
current_music_name = self.local_music_name_list[self.current_music_index].replace(".mp3", "")
if len(current_music_name) > MAX_MUSIC_NAME_LEN:
current_music_name = current_music_name[0:MAX_MUSIC_NAME_LEN] + "..."
self.current_music_static_text.SetLabelText(current_music_name)
# step6开启新线程追踪歌词
self.display_lyric()
def play_index_music(self, music_index):
'''
播放指定索引的音乐
:return:
'''
self.current_music_index = music_index
# 载入音乐
self.play_music()
def play_stop_music(self, evt):
if self.music.get_busy() or self.IsPaused: # 有音乐在播放,需要暂停,或者音乐暂停中
if 1 == self.current_music_state:
print("有音乐在播放,需要暂停")
self.music.pause()
self.current_music_state = 0
self.IsPaused = True
self.play_stop_button.SetBitmap(self.play_bmp)
else: # 恢复暂停的音乐
self.music.unpause()
self.current_music_state = 1
self.IsPaused = False
self.play_stop_button.SetBitmap(self.stop_bmp)
else: # 重新载入音乐
self.play_music()
def play_last_music(self, evt):
# 计算上一首音乐的名字和路径
if self.current_music_index > 0:
self.play_index_music(self.current_music_index - 1)
else:
self.play_index_music(0)
def play_next_music(self, evt):
# 计算下一首音乐的名字和路径
if self.current_music_index < len(self.local_music_name_list) - 1:
self.play_index_music(self.current_music_index + 1)
else:
self.play_index_music(len(self.local_music_name_list) - 1)
def change_volume(self, evt):
'''
修改音量
:param evt:
:return:
'''
obj = evt.GetEventObject()
val = obj.GetValue()
self.volume = float(val / 100)
self.music.set_volume(self.volume)
def download_music(self, evt):
'''
下载音乐
:param evt:
:return:
'''
# 获取文本框中输入的下载地址
music_down_url = self.input_url_text_ctrl.GetValue()
# 给下载的音乐在本地确定一个存储地址
down_music_path = os.path.join(self.local_music_folder, datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S') + ".mp3")
before_music_name = self.local_music_name_list[self.current_music_index]
# 开始下载
urllib.request.urlretrieve(music_down_url, down_music_path)
# 下载完成后,重新绘制音乐列表面板
self.draw_music_list_panel()
# 调整当前音乐的索引
for index in range(len(self.local_music_name_list)):
if before_music_name == self.local_music_name_list[index]:
self.current_music_index = index
def get_lyrics(self):
'''
读取歌词不带时间标记
:param lyrics_file_path:
:return:
'''
# 获取当前播放的音乐的歌词的完整路径
current_lyric_path = self.get_lyric_path()
if current_lyric_path is None or not os.path.exists(current_lyric_path):
return ["纯音乐或暂无歌词"]
# 打开歌词文件,读取其中的内容
with open(current_lyric_path, 'r', encoding="utf-8") as file_pointer:
content_list = file_pointer.readlines()
# 用一个list记录歌词
lyrics_list = []
# 我们只要歌词部分,不要开头的歌名和作者介绍,因为歌名和作者介绍不带时间
# 不方便我们进行歌词的追踪
for content in content_list:
# 用一个正则表达式过滤出歌词部分
if re.match(LYRIC_ROW_REG, content):
lyric_clause = content.replace('\n', '')[10:]
lyrics_list.append(lyric_clause)
return lyrics_list
def display_lyric(self):
lyric_refersh_thread = Thread(target=self.refersh_lyrics)
lyric_refersh_thread.start()
def parse_lyrics(self):
current_lyric_path = self.get_lyric_path()
if current_lyric_path is None:
content_list = ["[00:00.00]暂无歌词"]
else:
# 读文件内容
with open(current_lyric_path, 'r', encoding="utf-8") as file_pointer:
content_list = file_pointer.readlines()
lyrics_list = []
for content in content_list:
if re.match(LYRIC_ROW_REG, content):
time_lyric = dict()
start_time = float(content[1:3]) * 60 + float(content[4:6]) + float(content[7:9]) / 100
index_of_right_blank = content.index(']')
time_lyric[start_time] = content.replace('\n', '')[index_of_right_blank + 1:]
lyrics_list.append(time_lyric)
return lyrics_list
def refersh_lyrics(self):
'''
刷新歌词子线程
:return:
'''
lyrics_time_dict_list = self.parse_lyrics()
relative_start_index = 0 # 相对起始歌词索引
while self.music.get_busy(): # 播放中
current_time = float(self.music.get_pos() / 1000)
for lyric_index, lyrics_time_dict in enumerate(lyrics_time_dict_list):
lyric_time = list(lyrics_time_dict.keys())[0]
if math.fabs(lyric_time - current_time) < 0.7:
# 当歌词已经超过底部了,则刷新歌词面板,展示第二页的歌词
if lyric_index > 0 and lyric_index % MAX_LYRIC_ROW == 0:
relative_start_index = lyric_index
self.redraw_music_lyric_panel(start_index=relative_start_index)
self.lyrcis_static_text[lyric_index - relative_start_index].SetOwnForegroundColour((227, 62, 51))
# 这句话千万不能少少了颜色不会刷新来自调试了4个小时的忠告
self.lyrcis_static_text[lyric_index - relative_start_index].Refresh()
break
time.sleep(1)
def draw_music_lyric_panel(self):
'''
歌词所在的面板的控制
:return:
'''
self.music_lyric_panel = wx.Panel(self, id=-1, pos=(400, 60), size=(self.width - 400, self.height - 160))
# 获取歌词
lyric_list = self.get_lyrics()
# 展示歌词
for lyric_index in range(MAX_LYRIC_ROW):
if lyric_index < len(lyric_list):
lyric = lyric_list[lyric_index]
else:
lyric = ""
lyric_row = wx.StaticText(self.music_lyric_panel, -1, lyric, pos=(300, 30 * lyric_index + 10),
size=(200, -1), style=wx.ALIGN_CENTER_HORIZONTAL)
lyric_row.SetOwnForegroundColour((255, 255, 255))
self.lyrcis_static_text.append(lyric_row)
def get_lyric_path(self):
current_music_path = self.get_path_by_name(self.local_music_name_list[self.current_music_index])
current_lyric_path = current_music_path.replace(".mp3", ".lrc")
if os.path.exists(current_lyric_path):
return current_lyric_path
else:
return None
if __name__ == "__main__":
app = wx.App()
frame = mainFrame()
frame.Show()
app.MainLoop()
wx.Exit()

@ -0,0 +1,77 @@
[00:00.000] 作曲 : 野田洋次郎
[00:00.721] 作词 : 野田洋次郎
[00:04.067]Born with nothing in my hands
[00:07.026]I stumbled upon this place
[00:10.513]Falling through a crack in time
[00:13.895]I was writhing in pain
[00:17.217]When those who make it in this age
[00:20.564]Are only those whove learned how to take
[00:23.799]And everyone whose given up
[00:27.220]Where do we all take a breath?
[00:44.568]Governors and gods alike
[00:47.575]Try to turn the other cheek
[00:50.923]But even if you look away
[00:54.351]The truth is always facing you
[00:57.818]Courage and the strength of hope
[01:01.058]the magical bond we share
[01:04.452]We grow up only to forget
[01:07.834]How we ever use them here
[01:11.255]But same as you were on that day
[01:14.617]I see you still standing there
[01:17.955]Glowing in your innocence
[01:21.356]You were always standing there
[01:24.935]When the world turned its back on you
[01:28.091]You found a way to stand and fight
[01:31.501]Ready to face it all
[01:34.735]I see you here shining bright
[01:38.353]I need to know if theres still anything that love can do
[01:44.766]I need to know if theres still anything that I can do
[01:57.797]You are the one who found my courage and I knew
[02:04.265]I wanna pay it back and spend it all on you
[02:11.046]You gave me love we shared its all because of you
[02:17.605]You are the reason, let me share this love with you
[02:23.681]I need to know if theres still anything that love can do
[02:30.439]I need to know if theres still anything that I can do
[02:56.400]What if our destiny
[02:59.464]Was just a roll of the dice
[03:02.902]Or if its up to the Gods
[03:06.071]And if they feel like playing nice
[03:09.582]A mission that we didnt choose
[03:12.891]Like armor that we cant remove
[03:16.294]Or maybe its a distant wish
[03:19.554]Something that we cant refuse
[03:23.256]Prayers that are never heard
[03:26.485]Reunions that never occur
[03:29.767]Arguments that never clear
[03:33.168]Hate that doesnt disappear
[03:36.851]I hear the voices that forgive
[03:39.903]I see them standing hand in hand
[03:43.390]But with its arm open wide
[03:46.583]The Earth embraces all it can
[03:50.117]I need to know if theres still anything that love can do
[03:56.618]I need to know if theres still anything that I can do
[04:09.592]You are the one who found my courage and I knew
[04:16.096]I wanna pay it back and spend it all on you
[04:22.764]This love we raise together shaped by me and you
[04:29.568]You are the reason, let me live this love with you
[04:35.622]I need to know if theres still anything that love can do
[04:42.259]I need to know if theres still anything that I can do
[04:49.976]So insignificant just you and me,
[04:52.577]So why were we given this dream
[04:56.432]And if this life is just going to end
[04:59.105]Tell me why were we allowed to feel hope
[05:03.034]If its just gonna slip out of my hands
[05:05.909]Then why even give it to me
[05:10.046]Isnt it sad how we try to hold on
[05:12.431]Knowing one day itll all be gone
[05:15.850]Or maybe its beautiful
[05:20.974]Answer me
[05:47.217]All these love songs we hear
[05:50.294]Already (yeah) theyve been sung to death
[05:53.612]All the movies that weve seen
[05:56.777]Theyve said everything they can
[06:00.311]But somehow you and me
[06:03.599]Fell into this wilderness
[06:07.002]But still I need to know
[06:13.681]I need to know if theres still anything that love can do
[06:20.275]I need to know if theres still anything that I can do

@ -0,0 +1,60 @@
[00:00.000] 作词 : 易家扬
[00:01.000] 作曲 : 林俊杰
[00:02.000] 编曲 : 吴庆隆
[00:03.000] 制作人 : 林俊杰
[00:32.021]光 拿乌云揉成团
[00:36.560]像鲸鱼吻着浪
[00:40.332]叫我 和你 去飞翔
[00:45.823]人 老无语后落单
[00:50.614]别跟丢了天空 沙滩
[00:56.087]挣脱 回忆 壮胆
[01:02.347]
[01:02.681]裹着心的光 很暖 与你 有关
[01:10.174]有梦就听得到 用爱呼应感叹
[01:16.967]心里裹着光 的人 世界 很宽
[01:24.443]出发就走得到 来时路不会被 剪断
[01:33.990]
[01:47.759]当 那无名领头羊
[01:52.800]替明天找希望
[01:55.988]说嘿 有我 别心慌
[02:01.844]来 学萤火虫冥想
[02:06.601]在昏暗中静默 发亮
[02:11.960]是否 有梦 当然
[02:18.154]
[02:18.718]裹着心的光 很响 说了 别慌
[02:26.147]它说孤单很好 信念创造不凡
[02:32.871]心里裹着光 的人 初衷 不换
[02:40.298]誓言让心不老 带那些梦探索 远方
[02:49.979]
[02:50.762]一路有雨 也有霜 月落无题江南
[02:58.390]如我面对太阳 如你追希望
[03:04.582]一诺冒险 就得闯 单板翻越冰川
[03:12.543]未来不缺翅膀 冰雨和闷雷 别管
[03:22.090]
[03:22.657]裹着心的光 很响 说了 别慌
[03:29.516]它说孤单很好 信念创造不凡
[03:36.376]心里裹着光 的人 初衷 不换
[03:43.802]誓言让心不老 带那些梦探索 远方
[03:54.667]问那些年的梦 有多烫
[03:56.410] 配唱编写 : 林俊杰
[03:58.153] 制作协力 : 黄冠龙 ALEX.D/周信廷 SHiN CHOU/蔡沛蓁 Patti Tsai
[03:59.896] 键盘 : 吴庆隆
[04:01.639] 弦乐编写 : 吴庆隆
[04:03.382] 弦乐录音监督 : 胡静成
[04:05.125] 第一小提琴 : 张浩/庞阔/张琴/杨爽/刘睿/颜柯/张晗/高言
[04:06.868] 第二小提琴 : 简培/侯宇红/闫红/李若云/高一凡/倪冰雪
[04:08.611] 中提琴 : 李辉/李季泽/毕芳/方振华
[04:10.354] 大提琴 : 张平/郎莹/王瑶/石云博
[04:12.097] 大提琴独奏 : 郎莹
[04:13.840] 吉他 : 黄冠龙 ALEX.D
[04:15.583] 低音吉他 : 甯子达 Michael Ning
[04:17.326] 鼓 : Brendan Buckley
[04:19.069] 和声编写 : 林俊杰
[04:20.812] 和声 : 林俊杰
[04:22.555] 录音室 : THE JFJ SINGULARITY (Taipei)/JFJ SANCTUARY (Taipei)/Reflector Music Studio (Los Angeles)/九紫天成录音棚 (Beijing)
[04:24.298] 录音师 : 林俊杰/黄冠龙 ALEX.D/Brendan Buckley/刘璆
[04:26.041] 混音室 : mixHaus Studios (Los Angeles)
[04:27.784] 混音师 : Richard Furch
[04:29.527] 后期母带处理制作人 : 林俊杰
[04:31.270] 后期母带处理录音室 : 馒头音乐工作室
[04:33.013] 后期母带处理录音师 : 孙仲舒

@ -0,0 +1 @@
Subproject commit fc0a266315596f7f92ce7352225f05ec1de06594

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Loading…
Cancel
Save