查看: 3340|回复: 5

[通用发布] 简单同步歌词显示

[复制链接]
梦石
0
星屑
76
在线时间
1379 小时
注册时间
2012-7-5
回帖
1643

开拓者

发表于 2014-4-12 17:42:23 | 显示全部楼层 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有账号?注册会员

×
本帖最后由 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)】
[pre lang="ruby" line="1" file="lrc.txt"]class String
  @@MultiByteToWideChar  = Win32API.new('kernel32', 'MultiByteToWideChar', 'ilpipi', 'i')
  @@WideCharToMultiByte  = Win32API.new('kernel32', 'WideCharToMultiByte', 'ilpipipp', 'i')
  def s2u
    i = @@MultiByteToWideChar.call(0, 0, self, -1, nil, 0)
    buffer = "\0" * (i*2)
    @@MultiByteToWideChar.call(0, 0, self, -1, buffer, buffer.size / 2)
    i = @@WideCharToMultiByte.call(65001, 0, buffer, -1, nil, 0, nil, nil)
    result = "\0" * i
    @@WideCharToMultiByte.call(65001, 0, buffer, -1, result, result.size, nil, nil)
    result.chop!
    return result
  end
end

class Lrc
  #--------------------------------------------------------------------------
  # ● 初始化
  #--------------------------------------------------------------------------
  def initialize(songname)
    # 获取歌词
    lrc = File.open("Audio/BGM/#{songname}.lrc").read.s2u.split("\n")
    # 分析歌词
    @content = []
    for line in lrc
      unless line[/(?<=\[)\d{2}:\d{2}.\d{2}(?=\])/].nil?
        t = line.split(']').size - 1
        txt = line.split(']').size == 1 ? "" : line[10*t..-1]
        for i in 0..t
          l = line[(1+10*i)..(8+10*i)]
          min   = l.split(':')[0].to_i
          a     = l.split(':')[1].to_s
          sec   = a.split('.')[0].to_i
          msec  = a.split('.')[1].to_i
          unless min*60000+sec*1000+msec*10 == 0
            @content.push([min*60000+sec*1000+msec*10, txt])
          end
        end
      end
    end
    @content.sort!
    @content.push([1800000, ''])
    # 画图
    @sprite = Sprite.new
    @sprite.bitmap = Bitmap.new(640,22)
    @sprite.x,@sprite.y = 0,458
    #@content.each_with_index{|l,i|@sprite.bitmap.draw_text(0,i*22+2,640,22,l[1],1)}
    # 记时开始
    @temp = ""
    start
  end
  #--------------------------------------------------------------------------
  # ● 刷新精灵
  #--------------------------------------------------------------------------
  def update
    @sprite.opacity += 25 unless @sprite.opacity == 255
    if now_lrc != @temp
      @sprite.bitmap.clear
      @sprite.bitmap.draw_text(0,0,640,22,now_lrc,1)
      @temp = now_lrc
      @sprite.opacity = 0
    end
  end
  #--------------------------------------------------------------------------
  # ● 释放精灵
  #--------------------------------------------------------------------------
  def dispose
    @sprite.bitmap.dispose
    @sprite.dispose
    @temp = nil
    @content = nil
    @start_time = nil
  end
  #--------------------------------------------------------------------------
  # ● 获取当前一句歌词
  #--------------------------------------------------------------------------
  def now_lrc
    @content.each_with_index do | t, i |
      return @content[i-1][1] if current_time - t[0] <= 0
    end
  end
  #--------------------------------------------------------------------------
  # ● 调整纵坐标
  #--------------------------------------------------------------------------
  def y
    return @sprite.y
  end
  def y=(int)
    @sprite.y = int
  end
  #--------------------------------------------------------------------------
  # ● 获取当前毫秒数
  #--------------------------------------------------------------------------
  def msec
    t = Time.now
    t.to_i * 1000 + t.usec / 1000
  end
  #--------------------------------------------------------------------------
  # ● 开始 重置 start_time
  #--------------------------------------------------------------------------
  def start
    @start_time = msec
  end
  #--------------------------------------------------------------------------
  # ● 获取时间
  #--------------------------------------------------------------------------
  def current_time
    msec - @start_time
  end
end
[/pre]
【测试用脚本】
[pre lang="ruby" line="1"]l = Lrc.new("无前缀后缀歌曲名") # 如 "周杰伦 - 枫"
Audio.bgm_play("带前缀后缀的歌曲名") # 如 "Audio/BGM/周杰伦 - 枫.mp3"
loop{Graphics.update;l.update}[/pre]
【补(luan)救(xiang)】
    1.淡入淡出特效什么的在update那里加点东西就行了【在下就偷懒不写了
    2.加入update队列可以考虑直接alias Graphics.update【在下真是垢了
    3.范例真的就不需要了吧?!  

评分

参与人数 2星屑 +40 收起 理由
taroxd + 20 糖
无脑之人 + 20 虽然没仔细看但是还是塞糖吧w

查看全部评分


  -fk: -azogi:

…あたしは天

梦石
0
星屑
2308
在线时间
4033 小时
注册时间
2010-10-4
回帖
10548

开拓者贵宾

发表于 2014-4-13 17:22:13 | 显示全部楼层
本帖最后由 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-15 12:17
api什么的是MTV脚本里通过调用dll获取了时间,另外确实压缩版的还不支持,在下有空改一改  发表于 2014-4-15 12:14
回复

使用道具 举报

故九江太守

梦石
0
星屑
314
在线时间
2158 小时
注册时间
2012-12-5
回帖
4323
发表于 2014-4-14 20:02:36 | 显示全部楼层
歌词文件?是酷狗音乐用的那种吗?

点评

酷狗我没记错的话它的歌词文件是另一种格式。。用记事本打开是乱码  发表于 2014-4-15 12:19
回复

使用道具 举报

…あたしは天

梦石
0
星屑
2308
在线时间
4033 小时
注册时间
2010-10-4
回帖
10548

开拓者贵宾

发表于 2014-4-19 20:42:54 | 显示全部楼层
本帖最后由 taroxd 于 2014-4-19 21:07 编辑

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

[pre lang="ruby" line="1"]
# @content = []
# 迭代每一行 do |line|
tags = line.slice! /(?:\[\d\d:\d\d:\d\d\])+/
tags.scan /\[(\d\d):(\d\d):(\d\d)\]/ do |(min, sec, msec)|
  @contents.push [min.to_i * 60000 + sec.to_i * 1000 + msec.to_i * 10, line]
end if tags
# @content.sort!
[/pre]
回复

使用道具 举报

梦石
0
星屑
50
在线时间
310 小时
注册时间
2012-10-14
回帖
170
发表于 2014-12-7 15:31:27 | 显示全部楼层
看你这么多帖子都不给范例恨死你了啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊!~!!!!!{:4_147:}
回复

使用道具 举报

梦石
0
星屑
118
在线时间
85 小时
注册时间
2013-7-24
回帖
167
发表于 2014-12-12 19:23:16 | 显示全部楼层
好久不来第一个就看到了您的帖子
歌词显示可以设置字体么

点评

稍微看一下F1的bitmap和font就行了  发表于 2014-12-13 12:06
终于放假了,正在尝试肝出一款新游戏
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部