Class: MPAInfo::Header

Inherits:
Object
  • Object
show all
Defined in:
lib/mpainfo/header.rb

Overview

A class for parsing MPEG Audio Frame Headers

Constant Summary collapse

MODE_NAMES =

Enumeration of the names of each of the Modes as returned by #mode.

[
  'Stereo',
  'Joint-Stereo',
  'Dual',
  'Mono'
]

Instance Method Summary collapse

Constructor Details

#initialize(data = nil) ⇒ Header

Create a new MPEG Audio Header object If the data is given, then is is parsed as a header


42
43
44
# File 'lib/mpainfo/header.rb', line 42

def initialize(data = nil)
  parse(data) unless data.nil?
end

Instance Method Details

#bitrateInteger

Return the bitate in kbps

Returns:

  • (Integer)

126
127
128
# File 'lib/mpainfo/header.rb', line 126

def bitrate
  BITRATE_TABLE[version - 1][layer - 1][bitrate_index]
end

#bitrate_indexInteger

Returns the index of the bitrate number

Returns:

  • (Integer)

120
121
122
# File 'lib/mpainfo/header.rb', line 120

def bitrate_index
  (@header >> 12) & 0x0F
end

#channelsInteger

Returns the number of channels

  1. Mono

  2. Stereo, Joint-Stereo, Dual Channel

Returns:

  • (Integer)

170
171
172
173
174
175
176
# File 'lib/mpainfo/header.rb', line 170

def channels
  if mode == 3 # Mono
    1
  else
    2
  end
end

#copyright?Boolean

Returns true if the Copyright Bit is set

Returns:

  • (Boolean)

185
186
187
# File 'lib/mpainfo/header.rb', line 185

def copyright?
  ((@header >> 3) & 0x01) == 0x01
end

#emphasisInteger

Returns the emphasis setting value

Returns:

  • (Integer)

196
197
198
# File 'lib/mpainfo/header.rb', line 196

def emphasis
  @header & 0x03
end

#emphasis_stringString

Returns emphasis setting as a string

Returns:

  • (String)

202
203
204
205
206
207
208
209
210
211
# File 'lib/mpainfo/header.rb', line 202

def emphasis_string
  case emphasis
  when 0x00
    'None'
  when 0x01
    '50/15 ms'
  when 0x03
    'CCIT J.17'
  end
end

#error_protection?Boolean

Returns true if Error Protecting (CRC) is enabled for this frame

Returns:

  • (Boolean)

114
115
116
# File 'lib/mpainfo/header.rb', line 114

def error_protection?
  ((@header >> 16) & 0x01) != 0x01
end

#extension?Boolean

Return the Private Extension bit

Returns:

  • (Boolean)

148
149
150
# File 'lib/mpainfo/header.rb', line 148

def extension?
  (@header >> 8) & 0x01 == 0x01
end

#layerInteger

Returns the layer number

  1. Layer 1

  2. Layer 2 (aka MP2)

  3. Layer 3 (aka MP3)

Returns:

  • (Integer)

109
110
111
# File 'lib/mpainfo/header.rb', line 109

def layer
  4 - ((@header >> 17) & 0x03)
end

#lengthInteger

Returns the length of the MPEG Audio frame (in bytes)

Returns:

  • (Integer)

231
232
233
234
235
236
237
238
# File 'lib/mpainfo/header.rb', line 231

def length
  pad = padding? ? 1 : 0
  if layer == 1
    (12000 * bitrate / samplerate + pad) * 4
  else
    144000 * bitrate / samplerate + pad
  end
end

#modeInteger

Returns the mode number See the MODE_NAMES for the mapping.

Returns:

  • (Integer)

155
156
157
# File 'lib/mpainfo/header.rb', line 155

def mode
  (@header >> 6) & 0x03
end

#mode_extensionInteger

Returns the 2-bit value of the Mode Extension

Returns:

  • (Integer)

180
181
182
# File 'lib/mpainfo/header.rb', line 180

def mode_extension
  (@header >> 4) & 0x03
end

#mode_stringString

Returns the name of the mode (Mono, Stereo…)

Returns:

  • (String)

161
162
163
# File 'lib/mpainfo/header.rb', line 161

def mode_string
  MODE_NAMES[mode]
end

#original?Boolean

Returns true if the Original Bit is set

Returns:

  • (Boolean)

190
191
192
# File 'lib/mpainfo/header.rb', line 190

def original?
  ((@header >> 2) & 0x01) == 0x01
end

#padding?Boolean

Returns padding bit for the frame

Returns:

  • (Boolean)

143
144
145
# File 'lib/mpainfo/header.rb', line 143

def padding?
  (@header >> 9) & 0x01 == 0x01
end

#parse(data) ⇒ Object

Parse the header of a MPEG Audio Frame

Returns true if the header was parsed Use the #valid? method to check if the header was valid


50
51
52
53
54
55
56
57
58
59
# File 'lib/mpainfo/header.rb', line 50

def parse(data)
  if data.length >= 4
    # Convert 4-byte header to unsigned big-endian integer
    @header = data.unpack('N').first
    true
  else
    @header = 0
    false
  end
end

#samplerateInteger

Returns the samplerate of the audio (in Hz)

Returns:

  • (Integer)

138
139
140
# File 'lib/mpainfo/header.rb', line 138

def samplerate
  SAMPLERATE_TABLE[version - 1][samplerate_index]
end

#samplerate_indexInteger

Returns the sample rate index

Returns:

  • (Integer)

132
133
134
# File 'lib/mpainfo/header.rb', line 132

def samplerate_index
  (@header >> 10) & 0x03
end

#samplesInteger

Returns the number of samples contained in the frame

Returns:

  • (Integer)

215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/mpainfo/header.rb', line 215

def samples
  if layer == 1
    384
  elsif layer == 2
    1152
  elsif layer == 3
    if version == 1
      1152
    else
      576
    end
  end
end

#syncwordInteger

Returns the Sync Word (first 11-bites of the frame) For a valid MPEG Audio Frame, this should always return 0x07FF

Returns:

  • (Integer)

64
65
66
67
# File 'lib/mpainfo/header.rb', line 64

def syncword
  # Top 11-bits
  (@header >> 21) & 0x07FF
end

#to_sString

Returns a string summary of the format

Returns:

  • (String)

253
254
255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/mpainfo/header.rb', line 253

def to_s
  if valid?
    format(
      '%s layer %d, %d kbps, %d Hz, %s',
      version_string,
      layer,
      bitrate,
      samplerate,
      mode_string
    )
  else
    'Invalid MPEG-Audio Header'
  end
end

#valid?Boolean

Returns true if this header is valid

Returns:

  • (Boolean)

241
242
243
244
245
246
247
248
249
# File 'lib/mpainfo/header.rb', line 241

def valid?
  return false if syncword != 0x07ff
  return false if layer.zero?
  return false if version.zero?
  return false if bitrate.zero?
  return false if samplerate.zero?
  return false if emphasis == 0x02
  true
end

#versionInteger

Returns the MPEG version number for the frame

  1. MPEG-1

  2. MPEG-2

  3. MPEG-2.5

Returns:

  • (Integer)

75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/mpainfo/header.rb', line 75

def version
  case (@header >> 19) & 0x03
  when 0x00
    3 # MPEG-2.5
  when 0x01
    0 # Reserved
  when 0x02
    2 # MPEG-2
  when 0x03
    1 # MPEG-1
  end
end

#version_stringString

Returns the name of the MPEG version

Returns:

  • (String)

90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/mpainfo/header.rb', line 90

def version_string
  case version
  when 1
    'MPEG-1'
  when 2
    'MPEG-2'
  when 3
    'MPEG-2.5'
  else
    'MPEG-??'
  end
end