class SMF::Sequence::RS

Public Class Methods

new(s, cb) click to toggle source
# File lib/smf/io.rb, line 76
def initialize(s, cb) @s, @cb = s, cb end

Public Instance Methods

read() click to toggle source
# File lib/smf/io.rb, line 259
def read
  begin
    rs = RS::PO.new(get_from_macbin || get_from_rmid || @s)
    ckid = rs.getn(4)
    unless ckid == 'MThd'
      @cb.error('not an SMF')
    end
    rs.skip(-4)
    until rs.eof?
      ckid = rs.getn(4)
      leng = rs.geti32
      body = rs.getn(leng)
      case ckid
      when 'MThd'
        read_header(body)
      when 'MTrk'
        read_track(body)
      else
        @cb.unknownchunk(ckid, body)
      end
    end
  rescue EOFError
    @cb.error('unexpected EOF')
  end
  @cb.result
end

Private Instance Methods

get_from_macbin() click to toggle source
# File lib/smf/io.rb, line 238
def get_from_macbin
  begin
    if @s[0, 1] == "\000" && @s[74,1] == "\000" &&
       @s[82,1] == "\000" && @s[65,4] == 'Midi'
      @s[128,@s[83,4].unpack('N')[0]]
    end
  rescue
  end
end
get_from_rmid() click to toggle source
# File lib/smf/io.rb, line 248
def get_from_rmid
  begin
    if @s[0,4] == 'RIFF' && @s[8,4] == 'RMID'
      @s[20,@s[16,4].unpack('V')[0]]
    end
  rescue
  end
end
read_header(s) click to toggle source
# File lib/smf/io.rb, line 78
def read_header(s)
  rs = RS::PO.new(s)
  format = rs.geti16
  ntrks = rs.geti16
  div1 = rs.getc
  div2 = rs.getc
  if (div1 & 0x80) == 0
    tc = nil
    division = div1 << 8 | div2
  else
    tc = 0x100 - div1
    division = div2
  end
  @cb.header(format, ntrks, division, tc)
end
read_meta(type, data) click to toggle source
# File lib/smf/io.rb, line 94
def read_meta(type, data)
  case type
  when 0x0
    rs = RS::PO.new(data)
    num = rs.geti16
    @cb.sequencenumber(num)
  when 0x1..0xf
    case type
    when 0x1; @cb.generalpurposetext(data)
    when 0x2; @cb.copyrightnotice(data)
    when 0x3; @cb.trackname(data)
    when 0x4; @cb.instrumentname(data)
    when 0x5; @cb.lyric(data)
    when 0x6; @cb.marker(data)
    when 0x7; @cb.cuepoint(data)
    when 0x8; @cb.programname(data)
    when 0x9; @cb.devicename(data)
    when 0xa; @cb.text0a(data)
    when 0xb; @cb.text0b(data)
    when 0xc; @cb.text0c(data)
    when 0xd; @cb.text0d(data)
    when 0xe; @cb.text0e(data)
    when 0xf; @cb.text0f(data)
    end
  when 0x20
    rs = RS::PO.new(data)
    ch = rs.getc
    @cb.channelprefix(ch)
  when 0x21
    rs = RS::PO.new(data)
    num = rs.getc
    @cb.midiport(num)
  when 0x2f
    @cb.endoftrack
  when 0x51
    rs = RS::PO.new(data)
    tempo = rs.geti24
    @cb.settempo(tempo)
  when 0x54
    rs = RS::PO.new(data)
    hr = rs.getc
    tc = [24, 25, 29, 30][(hr >> 5) & 0x3]
    hr &= 0x1f
    mn = rs.getc
    se = rs.getc
    fr = rs.getc
    ff = rs.getc
    @cb.smpteoffset(hr, mn, se, fr, ff, tc)
  when 0x58
    rs = RS::PO.new(data)
    nn = rs.getc
    dd = rs.getc
    cc = rs.getc
    bb = rs.getc
    @cb.timesignature(nn, dd, cc, bb)
  when 0x59
    rs = RS::PO.new(data)
    sf = rs.getc
    mi = rs.getc
    sf = RS::PO.u2s(sf, 8)
    @cb.keysignature(sf, mi)
  when 0x7f
    @cb.sequencerspecific(data)
  else
    @cb.unknownmeta(type, data)
  end
end
read_track(s) click to toggle source
# File lib/smf/io.rb, line 162
def read_track(s)
  @cb.track_start
  rs = RS::PO.new(s)
  running = 0
  until rs.eof?
    @cb.delta(rs.getl)
    stat = rs.getc
    if (stat & 0x80) == 0
      rs.skip(-1)
      stat = running
    else
      case stat
      when 0x80..0xef; running = stat
      when 0xf0..0xf7; running = 0
      end
    end
    case stat
    when 0x80..0x8f
      @cb.noteoff(stat & 0xf, rs.getc, rs.getc)
    when 0x90..0x9f
      @cb.noteon(stat & 0xf, rs.getc, rs.getc)
    when 0xa0..0xaf
      @cb.polyphonickeypressure(stat & 0xf, rs.getc, rs.getc)
    when 0xb0..0xbf
      n = rs.getc
      v = rs.getc
      if n < 0x78
        @cb.controlchange(stat & 0xf, n, v)
      else
        case n
        when 0x78; @cb.allsoundoff(stat & 0xf)
        when 0x79; @cb.resetallcontrollers(stat & 0xf)
        when 0x7a; @cb.localcontrol(stat & 0xf, v)
        when 0x7b; @cb.allnotesoff(stat & 0xf)
        when 0x7c; @cb.omnioff(stat & 0xf)
        when 0x7d; @cb.omnion(stat & 0xf)
        when 0x7e; @cb.monomode(stat & 0xf, v)
        when 0x7f; @cb.polymode(stat & 0xf)
        end
      end
    when 0xc0..0xcf
      @cb.programchange(stat & 0xf, rs.getc)
    when 0xd0..0xdf
      @cb.channelpressure(stat & 0xf, rs.getc)
    when 0xe0..0xef
      lsb = rs.getc
      msb = rs.getc
      val = (lsb | msb << 7) - 0x2000
      @cb.pitchbendchange(stat & 0xf, val)
    when 0xf0, 0xf7
      len = rs.getl
      data = rs.getn(len)
      if stat == 0xf0
        @cb.exclusivef0(data)
      else
        @cb.exclusivef7(data)
      end
    when 0xff
      type = rs.getc
      len = rs.getl
      data = rs.getn(len)
      read_meta(type, data)
    else
      until rs.eof?
        unless (rs.getc & 0x80) == 0
          rs.skip(-1)
          break
        end
      end
    end
  end
  @cb.track_end
end