class AudioWaveform::WaveformDataFile

Provides access to audio waveform data, and serialization to and from binary and JSON data formats.

Constants

FLAG_8_BIT
HEADER_FORMAT

Header format: version - 4 byte signed integer flags - 4 byte unsigned integer sample_rate - 4 byte signed integer samples_per_pixel - 4 byte signed integer size - 4 byte unsigned integer

HEADER_SIZE

Public Class Methods

new(args) click to toggle source

@param args [Hash]

@option args [String] :filename Loads the specified binary waveform data

file.

@option args [Integer] :sample_rate @option args [Integer] :samples_per_pixel @option args [Integer] :bits @option args [Numeric, nil] :start_time Start time, in seconds, or nil

if no start time to be set.
# File lib/audio_waveform/waveform_data_file.rb, line 21
def initialize(args)
  if args[:filename]
    read(args[:filename])
  else
    self.sample_rate       = args[:sample_rate]
    self.samples_per_pixel = args[:samples_per_pixel]
    self.bits              = args[:bits]
    self.start_time        = args[:start_time]

    @data = []
  end
end

Public Instance Methods

append(min_sample, max_sample) click to toggle source

Appends a waveform minimum/maximum pair.

@param min_sample [Integer] Minimum audio sample amplitude value. @param max_sample [Integer] Maximum audio sample amplitude value.

@return [WaveformDataFile] The current object.

# File lib/audio_waveform/waveform_data_file.rb, line 185
def append(min_sample, max_sample)
  @data << min_sample
  @data << max_sample

  self
end
bits() click to toggle source

@return [Integer] Resolution of waveform data points, either 8 or 16 bits.

# File lib/audio_waveform/waveform_data_file.rb, line 73
def bits
  @bits
end
bits=(bits) click to toggle source

Sets the resolution of waveform data points.

@param bits [Integer] Number of bits, must be either 8 or 16 bits

# File lib/audio_waveform/waveform_data_file.rb, line 81
def bits=(bits)
  if bits != 8 && bits != 16
    raise Error, "Invalid bits: #{bits}"
  else
    @bits = bits
  end
end
max_sample(index) click to toggle source

@return [Integer] The maximum waveform data point at the specified index.

# File lib/audio_waveform/waveform_data_file.rb, line 200
def max_sample(index)
  @data[2 * index + 1]
end
min_sample(index) click to toggle source

@return [Integer] The minimum waveform data point at the specified index.

# File lib/audio_waveform/waveform_data_file.rb, line 194
def min_sample(index)
  @data[2 * index]
end
sample_rate() click to toggle source

@return [Integer] Audio sample rate, in Hz.

# File lib/audio_waveform/waveform_data_file.rb, line 36
def sample_rate
  @sample_rate
end
sample_rate=(sample_rate) click to toggle source

@param sample_rate [Integer] Audio sample rate, in Hz. Must be greater

than zero.
# File lib/audio_waveform/waveform_data_file.rb, line 43
def sample_rate=(sample_rate)
  if sample_rate <= 0
    raise Error, "Invalid sample rate: #{sample_rate}"
  else
    @sample_rate = sample_rate
  end
end
samples_per_pixel() click to toggle source

@return [Integer] Number of audio samples per waveform minimum/maximum

pair.
# File lib/audio_waveform/waveform_data_file.rb, line 54
def samples_per_pixel
  @samples_per_pixel
end
samples_per_pixel=(samples_per_pixel) click to toggle source

Sets the waveform data scaling.

@param samples_per_pixel [Integer] Number of audio samples per waveform

minimum/maximum pair.
# File lib/audio_waveform/waveform_data_file.rb, line 63
def samples_per_pixel=(samples_per_pixel)
  if samples_per_pixel <= 0
    raise Error, "Invalid samples per pixel: #{samples_per_pixel}"
  else
    @samples_per_pixel = samples_per_pixel
  end
end
save_as_binary(filename) click to toggle source

Writes the waveform data to file in binary (.dat) format.

@param filename [String] The name of the file to write. @return [WaveformDataFile] The current object.

# File lib/audio_waveform/waveform_data_file.rb, line 130
def save_as_binary(filename)
  File.open(filename, "wb") do |file|
    file.write(to_binary)
  end

  self
end
save_as_json(filename) click to toggle source

Writes the waveform data to file in JSON format.

@param filename [String] The name of the file to write. @return [WaveformDataFile] The current object.

# File lib/audio_waveform/waveform_data_file.rb, line 117
def save_as_json(filename)
  File.open(filename, "w") do |file|
    file.write(to_json)
  end

  self
end
size() click to toggle source

@return [Integer] Length of waveform data (number of minimum/maximum

value pairs).
# File lib/audio_waveform/waveform_data_file.rb, line 207
def size
  @data.size / 2
end
start_time() click to toggle source

@return [Numeric, nil] Start time of the waveform data, in seconds, or

nil if not set.
# File lib/audio_waveform/waveform_data_file.rb, line 92
def start_time
  @start_time
end
start_time=(start_time) click to toggle source

Sets the start time of the waveform data.

@param start_time [Numeric, nil] Start time of the waveform data, in

seconds, or nil if none.
# File lib/audio_waveform/waveform_data_file.rb, line 102
def start_time=(start_time)
  if start_time.nil?
    @start_time = nil
  elsif start_time < 0
    raise Error, "Invalid start time: #{start_time}"
  else
    @start_time = start_time
  end
end
to_binary() click to toggle source

@return [String] A binary representation of the waveform data file.

# File lib/audio_waveform/waveform_data_file.rb, line 164
def to_binary
  if @bits == 8
    flags  = FLAG_8_BIT
    format = "c*"
  else
    flags  = 0
    format = "s*"
  end

  output = encode_header(1, flags, @sample_rate, @samples_per_pixel, size)
  output += @data.pack(format)
  output
end
to_hash() click to toggle source

@return [Hash] A hash representation of the waveform data file.

# File lib/audio_waveform/waveform_data_file.rb, line 140
def to_hash
  obj = {
    sample_rate:       @sample_rate,
    bits:              @bits,
    samples_per_pixel: @samples_per_pixel,
    length:            @data.size / 2,
    data:              @data
  }

  if @start_time
    obj[:start_time] = @start_time
  end

  obj
end
to_json() click to toggle source

@return [String] A JSON representation of the waveform data file.

# File lib/audio_waveform/waveform_data_file.rb, line 158
def to_json
  JSON.generate(to_hash)
end

Private Instance Methods

decode_header(header) click to toggle source
# File lib/audio_waveform/waveform_data_file.rb, line 237
def decode_header(header)
  header.unpack(HEADER_FORMAT)
end
encode_header(version, flags, sample_rate, samples_per_pixel, size) click to toggle source
# File lib/audio_waveform/waveform_data_file.rb, line 233
def encode_header(version, flags, sample_rate, samples_per_pixel, size)
  [version, flags, sample_rate, samples_per_pixel, size].pack(HEADER_FORMAT)
end
read(filename) click to toggle source
# File lib/audio_waveform/waveform_data_file.rb, line 224
def read(filename)
  # TODO: loading of JSON data from file

  File.open(filename, "rb") do |file|
    size = read_header(file)
    read_data(file, size)
  end
end
read_data(file, size) click to toggle source

@param file [File] The input file to read from. @param size [Integer] Number of waveform data points to read.

# File lib/audio_waveform/waveform_data_file.rb, line 269
def read_data(file, size)
  if @bits == 8
    format = 'c*' # Array of 8-bit signed integers
  elsif @bits == 16
    format = 's*' # Array of 16-bit signed integers
  end

  length = size * (@bits / 8) * 2

  raw_data = file.read(length)

  if raw_data
    @data = raw_data.unpack(format)
  else
    @data = []
  end
end
read_header(file) click to toggle source

@param file [File] The input file to read from. @return [Integer] Number of waveform data points, from Length header field.

# File lib/audio_waveform/waveform_data_file.rb, line 244
def read_header(file)
  header = file.read(HEADER_SIZE)

  if header.nil? || header.bytesize != HEADER_SIZE
    raise Error, "Failed to read file header"
  end

  version, flags, self.sample_rate, self.samples_per_pixel, size = decode_header(header)

  if version != 1
    raise Error, "Cannot load data file version: #{version}"
  end

  if (flags & FLAG_8_BIT) != 0
    @bits = 8
  else
    @bits = 16
  end

  size
end