Project1

标题: 简单同步歌词显示 [打印本页]

作者: kuerlulu    时间: 2014-4-12 17:42
标题: 简单同步歌词显示
本帖最后由 kuerlulu 于 2014-4-19 20:25 编辑

【2014年4月19日20:24:45 更新】
    @taroxd 已更新,顺便加了些没用的= =
【惯(fei)例(hua)】做音乐游戏时为了校准时间出来的副产物
【特(bu)色(zu)】
    1.在下只给出脚本没给出范例(噗
    2.免dll
    3.没有淡入淡出等特效
    4.不会自动加入update队列
    5.在下说这么多缺点肯定没人看了
    6.歌曲和歌词文件请都放到Audio/BGM里
【正(jie)文(cao)】
RUBY 代码复制下载
  1. class String
  2.   @@MultiByteToWideChar  = Win32API.new('kernel32', 'MultiByteToWideChar', 'ilpipi', 'i')
  3.   @@WideCharToMultiByte  = Win32API.new('kernel32', 'WideCharToMultiByte', 'ilpipipp', 'i')
  4.   def s2u
  5.     i = @@MultiByteToWideChar.call(0, 0, self, -1, nil, 0)
  6.     buffer = "\0" * (i*2)
  7.     @@MultiByteToWideChar.call(0, 0, self, -1, buffer, buffer.size / 2)
  8.     i = @@WideCharToMultiByte.call(65001, 0, buffer, -1, nil, 0, nil, nil)
  9.     result = "\0" * i
  10.     @@WideCharToMultiByte.call(65001, 0, buffer, -1, result, result.size, nil, nil)
  11.     result.chop!
  12.     return result
  13.   end
  14. end
  15.  
  16. class Lrc
  17.   #--------------------------------------------------------------------------
  18.   # ● 初始化
  19.   #--------------------------------------------------------------------------
  20.   def initialize(songname)
  21.     # 获取歌词
  22.     lrc = File.open("Audio/BGM/#{songname}.lrc").read.s2u.split("\n")
  23.     # 分析歌词
  24.     @content = []
  25.     for line in lrc
  26.       unless line[/(?<=\[)\d{2}:\d{2}.\d{2}(?=\])/].nil?
  27.         t = line.split(']').size - 1
  28.         txt = line.split(']').size == 1 ? "" : line[10*t..-1]
  29.         for i in 0..t
  30.           l = line[(1+10*i)..(8+10*i)]
  31.           min   = l.split(':')[0].to_i
  32.           a     = l.split(':')[1].to_s
  33.           sec   = a.split('.')[0].to_i
  34.           msec  = a.split('.')[1].to_i
  35.           unless min*60000+sec*1000+msec*10 == 0
  36.             @content.push([min*60000+sec*1000+msec*10, txt])
  37.           end
  38.         end
  39.       end
  40.     end
  41.     @content.sort!
  42.     @content.push([1800000, ''])
  43.     # 画图
  44.     @sprite = Sprite.new
  45.     @sprite.bitmap = Bitmap.new(640,22)
  46.     @sprite.x,@sprite.y = 0,458
  47.     #@content.each_with_index{|l,i|@sprite.bitmap.draw_text(0,i*22+2,640,22,l[1],1)}
  48.     # 记时开始
  49.     [url=home.php?mod=space&uid=263426]@temp[/url] = ""
  50.     start
  51.   end
  52.   #--------------------------------------------------------------------------
  53.   # ● 刷新精灵
  54.   #--------------------------------------------------------------------------
  55.   def update
  56.     @sprite.opacity += 25 unless @sprite.opacity == 255
  57.     if now_lrc != @temp
  58.       @sprite.bitmap.clear
  59.       @sprite.bitmap.draw_text(0,0,640,22,now_lrc,1)
  60.       @temp = now_lrc
  61.       @sprite.opacity = 0
  62.     end
  63.   end
  64.   #--------------------------------------------------------------------------
  65.   # ● 释放精灵
  66.   #--------------------------------------------------------------------------
  67.   def dispose
  68.     @sprite.bitmap.dispose
  69.     @sprite.dispose
  70.     @temp = nil
  71.     @content = nil
  72.     @start_time = nil
  73.   end
  74.   #--------------------------------------------------------------------------
  75.   # ● 获取当前一句歌词
  76.   #--------------------------------------------------------------------------
  77.   def now_lrc
  78.     @content.each_with_index do | t, i |
  79.       return @content[i-1][1] if current_time - t[0] <= 0
  80.     end
  81.   end
  82.   #--------------------------------------------------------------------------
  83.   # ● 调整纵坐标
  84.   #--------------------------------------------------------------------------
  85.   def y
  86.     return @sprite.y
  87.   end
  88.   def y=(int)
  89.     @sprite.y = int
  90.   end
  91.   #--------------------------------------------------------------------------
  92.   # ● 获取当前毫秒数
  93.   #--------------------------------------------------------------------------
  94.   def msec
  95.     t = Time.now
  96.     t.to_i * 1000 + t.usec / 1000
  97.   end
  98.   #--------------------------------------------------------------------------
  99.   # ● 开始 重置 start_time
  100.   #--------------------------------------------------------------------------
  101.   def start
  102.     @start_time = msec
  103.   end
  104.   #--------------------------------------------------------------------------
  105.   # ● 获取时间
  106.   #--------------------------------------------------------------------------
  107.   def current_time
  108.     msec - @start_time
  109.   end
  110. end

【测试用脚本】
RUBY 代码复制
  1. l = Lrc.new("无前缀后缀歌曲名") # 如 "周杰伦 - 枫"
  2. Audio.bgm_play("带前缀后缀的歌曲名") # 如 "Audio/BGM/周杰伦 - 枫.mp3"
  3. loop{Graphics.update;l.update}

【补(luan)救(xiang)】
    1.淡入淡出特效什么的在update那里加点东西就行了【在下就偷懒不写了
    2.加入update队列可以考虑直接alias Graphics.update【在下真是垢了
    3.范例真的就不需要了吧?!  
作者: taroxd    时间: 2014-4-13 17:22
本帖最后由 taroxd 于 2014-4-13 17:39 编辑

虽然我没用脚本,但是还是认真地看了一遍。

看了那行正则表达式,貌似不支持压缩版的lrc吧?
例:
[00:01:00][00:02:00]这是一句歌词,在第一秒和第二秒各唱一遍

话说为什么不直接在正则表达式里创建名字的引用……比如(?<min>)之类的

还有啊,读取个lrc似乎不需要用到win32api的吧……?lrc不是文本文件么……

另外我没记错的话Audio.bgm_play似乎可以省略后缀。至少wav和ogg可以

咦好像看到了我的音乐游戏的痕迹之类的?顺便期待音乐游戏。再顺便说一句校准可以用goldwave和BPMAnalyzer
作者: 你最珍贵    时间: 2014-4-14 20:02
歌词文件?是酷狗音乐用的那种吗?
作者: taroxd    时间: 2014-4-19 20:42
本帖最后由 taroxd 于 2014-4-19 21:07 编辑

我只吐槽乃的字符串处理为什么这么奇葩……

RUBY 代码复制
  1. # @content = []
  2. # 迭代每一行 do |line|
  3. tags = line.slice! /(?:\[\d\d:\d\d:\d\d\])+/
  4. tags.scan /\[(\d\d):(\d\d):(\d\d)\]/ do |(min, sec, msec)|
  5.   @contents.push [min.to_i * 60000 + sec.to_i * 1000 + msec.to_i * 10, line]
  6. end if tags
  7. # @content.sort!

作者: 1294669147    时间: 2014-12-7 15:31
看你这么多帖子都不给范例恨死你了啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊!~!!!!!{:4_147:}
作者: 1697665228    时间: 2014-12-12 19:23
好久不来第一个就看到了您的帖子
歌词显示可以设置字体么




欢迎光临 Project1 (https://rpg.blue/) Powered by Discuz! X3.1