jstrait / wavefile

A Ruby gem for reading and writing sound files in Wave format (*.wav)
https://wavefilegem.com
MIT License
209 stars 24 forks source link

Mix 2 wav files. #31

Closed ksbek closed 4 years ago

ksbek commented 4 years ago

Hello,

This gem is useful and I'm very thanks to you. I have one question. Using your gem, can I mix 2 wave files and set the volume for each track? Looking forward your answer.

jstrait commented 4 years ago

Thanks! I’m glad the gem is useful.

Yes, two wave files can be mixed, and the volume for each file adjusted. The WaveFile gem doesn’t directly do this for you, but you can do it by modifying the sample data you read out of the individual files.

First, if you need to know the basics of how digital audio works, check out https://www.joelstrait.com/digital_audio_primer/.

Adjusting File Loudness

You can adjust the volume of a file by multiplying each sample by a scale factor. For example, if you read data from a file as floating point data (i.e. using :float when calling Format.new()), then each sample will be a value between -1.0 and 1.0. If you multiply each sample by a number greater than 1.0 it will make the file louder, and if you multiply by a number between 0.0 and 1.0 it will make the file quieter.

However, if any resulting samples are larger than 1.0 or less than -1.0, the file will sound distorted. This is because -1.0 and 1.0 are the minimum and maximum sample values, so any value below/above will be clamped to be -1.0 or 1.0. This results in clipping distortion.

Some example code:

require "wavefile"
include WaveFile

SCALE_FACTOR = 1.5

Writer.new("modified.wav", Format.new(:mono, :pcm_16, 44100)) do |writer|
  Reader.new("original.wav", Format.new(:mono, :float, 44100)).each_buffer do |buffer|
    buffer.samples.map! {|sample| sample * SCALE_FACTOR }
    writer.write(buffer)
  end
end

Mixing Files

To combine two files, take each pair of samples from the two files, add them together, and then write out the combined samples to a new file. For example:

However, like above, you’ll want to make sure the samples don’t go below -1.0 or above 1.0, or the audio will sound distorted (like the 2nd combined sample above). One simple way to avoid this is to average each pair of samples. That is, set each output sample to (sample1 + sample2) / 2.

Hope this helps!

ksbek commented 4 years ago

Hello @jstrait,

Thank you for your reply. This is so useful information. It helps me.

Thanks again!