Class: BeatsWaveFile

Inherits:
WaveFile
  • Object
show all
Defined in:
lib/beatswavefile.rb

Overview

Adds some functionality to the WaveFile gem that allows for improved performance. The use of open_for_appending() allows a wave file to be written to disk in chunks, instead of all at once. This improves performance (and I would assume memory usage) by eliminating the need to store the entire sample data for the song in memory in a giant (i.e. millions of elements) array.

I’m not sure these methods in their current form are suitable for the WaveFile gem. If I figure out a better API I might add it to the WaveFile gem in the future, but until then I’m just putting it here. Since BEATS is a stand-alone app and not a re-usable library, I don’t think this should be a problem.

Instance Method Summary collapse

Instance Method Details

#calculate_duration(sample_rate, total_samples) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/beatswavefile.rb', line 47

def calculate_duration(sample_rate, total_samples)
  samples_per_millisecond = sample_rate / 1000.0
  samples_per_second = sample_rate
  samples_per_minute = samples_per_second * 60
  samples_per_hour = samples_per_minute * 60
  hours, minutes, seconds, milliseconds = 0, 0, 0, 0
  
  if total_samples >= samples_per_hour
    hours = total_samples / samples_per_hour
    total_samples -= samples_per_hour * hours
  end
  
  if total_samples >= samples_per_minute
    minutes = total_samples / samples_per_minute
    total_samples -= samples_per_minute * minutes
  end
  
  if total_samples >= samples_per_second
    seconds = total_samples / samples_per_second
    total_samples -= samples_per_second * seconds
  end
  
  milliseconds = (total_samples / samples_per_millisecond).floor
  
  return { :hours => hours, :minutes => minutes, :seconds => seconds, :milliseconds => milliseconds }
end

#open_for_appending(path) ⇒ Object

Writes the header for the wave file to path, and returns an open File object that can be used outside the method to append the sample data. WARNING: The header contains a field for the total number of samples in the file. This number of samples (and exactly this number of samples) must be subsequently be written to the file before it is closed or it won’t be valid and you won’t be able to play it.



18
19
20
21
22
23
# File 'lib/beatswavefile.rb', line 18

def open_for_appending(path)
  file = File.open(path, "wb")
  write_header(file, 0)
  
  return file
end

#write_header(file, sample_length) ⇒ Object



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/beatswavefile.rb', line 25

def write_header(file, sample_length)
  bytes_per_sample = (@bits_per_sample / 8)
  sample_data_size = sample_length * bytes_per_sample * @num_channels

  # Write the header
  header = CHUNK_ID
  header += [HEADER_SIZE + sample_data_size].pack("V")
  header += FORMAT
  header += FORMAT_CHUNK_ID
  header += [SUB_CHUNK1_SIZE].pack("V")
  header += [PCM].pack("v")
  header += [@num_channels].pack("v")
  header += [@sample_rate].pack("V")
  header += [@byte_rate].pack("V")
  header += [@block_align].pack("v")
  header += [@bits_per_sample].pack("v")
  header += DATA_CHUNK_ID
  header += [sample_data_size].pack("V")

  file.syswrite(header)
end