September 27, 2009
The WaveFile gem has been updated to version 0.3.0. It is now possible to modify several previously read-only fields, allowing you to convert a Wave file to a different format. For example, you can convert a mono file to stereo, or change the sample rate to alter the playback speed.
The code is hosted on GitHub, while the gem is hosted at GitHub hosted at Gemcutter. If you already have the old gem, you can update it to v0.3.0 with the following command:
sudo gem update wavefile
Otherwise, you can install it from scratch:
sudo gem install wavefile
Now for a blow-by-blow account of what is new. First, you can change the number of channels a file has, using num_channels=(). You can convert a mono file to stereo, or vice-versa.
w = WaveFile.new(:mono, 44100, 16) // Create a mono file
w.sample_data = <sample data goes here>
w.num_channels = 2 // Convert it to stereo
w.num_channels = :stereo // Same as line above
w.save("myfile.wav")
When converting a mono file to stereo, the sample data is duplicated for both the left and right channels. When converting a stereo file to mono, the sample data is mixed down to one channel.
Similarly, you can change the bit-rate using bits_per_sample=(). You can convert an 8-bit file to 16-bit, a vice-versa. (Converting an 8-bit file to 16-bit doesn’t actually increase the sound quality, since it’s not possible to add data that wasn’t present in the original file.)
w = Wavefile.new(:mono, 44100, 16) // Create an 16-bit file
w.sample_data = <sample data goes here>
w.bits_per_sample = 8 // Down-sample to 8-bit
w.save("myfile.wav")
The final new setter, sample_rate=(), predictably lets you change a file’s sample rate. Altering the sample rate has the effect of changing the playback speed. Increasing the sample rate causes the file to play faster and have a higher pitch; lowering it causes it to play slower and have a lower pitch.
w = Wavefile.new(:mono, 44100, 16) // Create a file with 44100Hz sample rate
w.sample_data = <sample data goes here>
w.sample_rate = 22050 // Lower playback speed and pitch by half
w.save("myfile.wav")
num_channels=(), bits_per_sample=(), and sample_rate=() only modify the file in memory. To save changes to disk, you have to call the save() method (shown in the examples above).
This release also adds two new methods for querying a file’s metadata. The duration() method returns a hash indicating the playback time of the file. The hash contains a value for the hours, minutes, seconds, and milliseconds of the playback time.
w = Wavefile.open("myfile.wav")
play_time = w.duration
# Example: {:hours => 0, :minutes => 3, :seconds => 12, :milliseconds => 345 }
You can use the new inspect() method to view all of a file’s metadata at once. It returns a multi-line string.
w = Wavefile.open("myfile.wav")
puts w.inspect()
# Example output:
# Channels: 2
# Sample rate: 44100
# Bits per sample: 16
# Block align: 4
# Byte rate: 176400
# Sample count: 498070
# Duration: 0h:0m:11s:294ms
Finally, this release contains a bug fix which expands the universe of files that Wavefile can successfully read. More specifically, files that contain extra chunks in addition to the format and data chunks can now be opened. Previously, these files would cause an error. (See the following link for an explanation of Wave file chunks: http://www.sonicspot.com/guide/wavefiles.html).
For information on the previous versions of WaveFile, see the following posts: