查看: 4353|回复: 7

[讨论] 大家看看这个获取MP3文件基本信息的脚本

[复制链接]
梦石
0
星屑
9557
在线时间
5074 小时
注册时间
2013-6-21
回帖
3459

开拓者贵宾剧作品鉴家

发表于 2014-11-21 16:31:24 | 显示全部楼层 |阅读模式

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

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

×
本帖最后由 RyanBern 于 2014-11-21 21:10 编辑

应@精灵使者 的要求,写了一个能够获取MP3文件信息的脚本。因为脚本还不是很成熟,不能完全解决MP3文件的信息获取问题,所以放在了RM讨论区,等完善之后可以考虑放到技术发布区。不过需要这个脚本的人不多,放上去也不知有什么用。

问题的核心在于如何获取MP3文件内容,我查了一堆资料(这里不得不吐槽我们的百度,所有的资料都是copy-paste的,而且都有错误),最后只能照样子写了一个。经过多次测试,该脚本不能处理所有MP3的信息,而且有时候会报错。大家看看我是不是遗漏了些什么。

由于XP的版本限制,无法读取中文信息,这点大家也帮忙想想有没有解决方法。

我参考的官方MP3数据结构网址:
www.id3.org

[pre lang="Ruby"]module Audio
  class Mp3Data
    attr_accessor :title
    attr_accessor :artist
    attr_accessor :album
    attr_accessor :year
    attr_accessor :comments
    attr_accessor :genre
    attr_accessor :track
  end
  def initialize
    @title = ""
    @artist = ""
    @album = ""
    @year = ""
    @comments = ""
    @genre = ""
    @track = ""
  end
  def self.get_playing_bgm_info_mp3_id3v2
    filename = "Audio/BGM/" + $game_system.playing_bgm.name + ".mp3"
    file = File.open(filename, "r")
    info = Mp3Data.new
    buffer = file.read(10)
    if buffer[0...3] == "ID3"
      size = buffer[6...10]
      total_size = (size[0]&0x7F) * 0x200000 + (size[1]&0x7F) * 0x4000 + (size[2]&0x7F) * 0x80 +(size[3]&0x7F)
      while total_size > 0
        buffer = file.read(10)
        break if buffer.nil?
        total_size -= 10
        tag = buffer[0...4]
        size = buffer[4...8]
        current_size = size[0] * 0x1000000 + size[1]* 0x10000 + size[2] * 0x100 + size[3]
        break if current_size == 0
        buffer = file.read(current_size)
        total_size -= current_size
        case tag
        when "TIT2"
          info.title = buffer.gsub(/[^0-9A-Za-z_ ]+/, "")
        when "TPE1"
          info.artist = buffer.gsub(/[^0-9A-Za-z_ ]+/, "")
        when "TYER"
          info.year = buffer.gsub(/[^0-9]+/, "")
        when "TRCK"
          info.track = buffer.gsub(/[^0-9\/]/, "")
        when "TALB"
          info.album = buffer.gsub(/[^0-9A-Za-z_ ]+/, "")
        when "TCON"
          info.genre = buffer.gsub(/[^0-9A-Za-z_ ]+/, "")
        when "COMM"
          info.comments = buffer.gsub(/[^0-9A-Za-z_ ]+/, "")
        end
      end
    end
    file.close
    return info
  end
end[/pre]

评分

参与人数 1星屑 +100 收起 理由
恐惧剑刃 + 100 塞糖

查看全部评分

梦石
0
星屑
9292
在线时间
2504 小时
注册时间
2011-5-20
回帖
14521

开拓者

发表于 2014-11-21 18:24:15 | 显示全部楼层
你可以拿永夜的原声带试试看···
[img]http://service.t.sina.com.cn/widget/qmd/5339802982/c02e16bd/7.png
回复

使用道具 举报

…あたしは天

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

开拓者贵宾

发表于 2014-11-21 18:53:10 | 显示全部楼层
吐槽一下,楼主查技术类资料竟然用百度……

点评

wiki吧···  发表于 2014-11-21 22:17
下次用google  发表于 2014-11-21 20:58
回复

使用道具 举报

精灵族の天使<

梦石
0
星屑
1712
在线时间
3039 小时
注册时间
2007-3-16
回帖
33092

开拓者贵宾

发表于 2014-11-21 23:36:11 | 显示全部楼层
本帖最后由 精灵使者 于 2014-11-22 00:07 编辑

那个,不需要获取MP3的ID3标签啦。
只需要获取正在播放的文件名就可以了的说。
补充:
精灵想要的是这种效果:
获取BGM音乐名,然后当BGM/ME变化的时候,在右下角显示BGM的名称(可以使用 - 符号分割,类似于: 01 - Title Theme - Kan Gao.mp3)之类的
也就是说屏幕右下角会显示:
BGM:
01
Title Theme
Kan Gao

点评

MP3格式感觉有硬伤。中间无法连续,有不可冲突的中断  发表于 2014-11-22 00:05
需要MP3格式啊,ME好像也可以用MP3吧?  发表于 2014-11-21 23:54
另外精灵想做成类似于和显示地图名脚本一样的效果的说。  发表于 2014-11-21 23:53
ME其实也可以么?  发表于 2014-11-21 23:52
这个针对ID3v2版本的,因为用ID3v2版本的最多,ID3v1版本的读取非常简单,但是好多MP3都没有ID3v1信息  发表于 2014-11-21 23:45
回复

使用道具 举报

路路 该用户已被删除
发表于 2014-11-22 01:32:41 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

梦石
0
星屑
9557
在线时间
5074 小时
注册时间
2013-6-21
回帖
3459

开拓者贵宾剧作品鉴家

 楼主| 发表于 2014-11-22 10:34:41 | 显示全部楼层
本帖最后由 精灵使者 于 2014-11-24 18:37 编辑
精灵使者 发表于 2014-11-21 23:36
那个,不需要获取MP3的ID3标签啦。
只需要获取正在播放的文件名就可以了的说。
补充:


写了一个循环显示BGM的脚本,没有做ME的,可以试试效果。
[pre lang="Ruby"]class BGM_Display
  def initialize
    @bgm = nil
    @me = nil
    @waiting = 0
    @sprite1 = Sprite.new
    @sprite2 = Sprite.new
    @sprite1.bitmap = Bitmap.new(160, 32)
    @sprite2.bitmap = Bitmap.new(160, 224)
    @sprite2.src_rect = Rect.new(0, 0, 160, 32)
    self.x = 480
    self.y = 416
    self.z = 999
    refresh
  end
  def refresh
    if @me == nil || @me.name ==""
      if @bgm == nil || @bgm.name == ""
        @sprite2.bitmap.clear
        return
      end
      @sprite1.bitmap.clear
      @sprite1.bitmap.draw_text(0, 0, 160, 32, "BGM:")
      @texts = @bgm.name.split(/-/)
    else
      @sprite1.bitmap.clear
      @sprite1.bitmap.draw_text(0, 0, 160, 32, "ME:")
      @texts = @me.name.split(/-/)
    end
    (0...@texts.size).each do |i|
      draw_item(i)
    end
  end
  def draw_item(i)
    x = 4
    y = 32 * (2 * i + 1)
    @sprite2.bitmap.fill_rect(x, y, 160, 32, Color.new(0,0,0,0))
    @sprite2.bitmap.draw_text(x, y ,160, 32, @texts)
  end
  def x=(x)
    @sprite1.x = x
    @sprite2.x = x
  end
  def y=(y)
    @sprite1.y = y
    @sprite2.y = y + 32
  end
  def z=(z)
    @sprite1.z = z
    @sprite2.z = z
  end
  def update
    if $game_temp.playing_me != nil
      @me = $game_temp.playing_me
      $game_temp.playing_me = nil
      refresh
      @sprite2.src_rect.y = 0
      return
    end
    if $game_system.playing_bgm != @bgm
      @bgm = $game_system.playing_bgm
      refresh
      @sprite2.src_rect.y = 0
      return
    end
    if @waiting > 0
      @waiting -= 1
      return
    end
    @sprite2.src_rect.y += 1
    if @sprite2.src_rect.y >= 192
      @sprite2.src_rect.y -= 192
      if @me != nil
        @me = nil
        refresh
      end
    end
    if @sprite2.src_rect.y % 64 == 32
      @waiting = 40
    end
  end
  def dispose
    @sprite1.bitmap.dispose
    @sprite2.bitmap.dispose
    @sprite1.dispose
    @sprite2.dispose
  end
end

class Game_Temp
  attr_accessor :playing_me
end

class Game_System
  alias rb_me_play_20141124 me_play
  def me_play(me)
    $game_temp.playing_me = me
    rb_me_play_20141124(me)
  end
end

class Scene_Map
  alias rb_main_20141122 main
  def main
    @bgm_display = BGM_Display.new
    rb_main_20141122
    @bgm_display.dispose
  end
  alias rb_update_20141122 update
  def update
    @bgm_display.update
    rb_update_20141122
  end
end[/pre]

点评

http://rm.66rpg.com/forum.php?mod=viewthread&tid=374031 召唤来看更新……  发表于 2014-11-25 15:40
好的!精灵立刻拿这个去测试去!没准会有新的发现呢。  发表于 2014-11-24 18:11
这个可以成为最终版了,窗口可以实时显示播放的BGM和ME,如果是BGM的话是循环显示,如果是ME的话就显示一次。  发表于 2014-11-24 14:04
其实BGM和ME都可以只显示一次就可以了。  发表于 2014-11-23 17:36
刚才想了下,打算这么处理:如果是ME的话就只滚动显示1次,无论ME是否播放完毕都切回BGM显示,这样做也是没有办法,毕竟ME和BGM播放机制不同  发表于 2014-11-23 09:49

评分

参与人数 1星屑 +100 收起 理由
精灵使者 + 100 认可答案

查看全部评分

回复

使用道具 举报

梦石
4
星屑
4454
在线时间
6784 小时
注册时间
2014-1-6
回帖
4956

开拓者

发表于 2014-11-25 11:52:11 | 显示全部楼层
可恶~,居然在这讨论这些我看不懂的东西!!

脚本!!,看我不把你学会!!
回复

使用道具 举报

寒

梦石
0
星屑
1049
在线时间
1391 小时
注册时间
2010-8-9
回帖
3301
发表于 2014-11-28 15:54:50 | 显示全部楼层
本帖最后由 寒冷魔王 于 2014-11-28 16:01 编辑

看楼主,猜语言,猜错了= =
还以为会用C#呢……

另外作为一名Java菜鸟想问一下Ruby怎样调用用Java写好的程序?
百度说是实例加载jar的,不过那个需不需要Java环境?

如果加载需要运行Java的话,我还是再学一学C#吧= =
回复

使用道具 举报

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

本版积分规则

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

在本版发帖返回顶部