MP3 fade in/out

May 23, 2009 at 7:59 AM

Hello

I was recommended to check NAudio - http://stackoverflow.com/questions/900383/c-and-mp3-fade-in-out - and I am wondering if I can use NAudio co create small samples from larger, main file. Now I was able to do the cutting with another tool, but I am still looking for an option to fade in/out start and end.

Could I use NAudio for that? I did not notice anything in docs..

Coordinator
Jun 8, 2009 at 8:39 AM

To fade audio in and out, you first need to convert to WAV. NAudio can convert MP3 to WAV. As for fading, it is not directly built in, but you can control the volume. I would write my own WaveStream derived class to perform fade ins and outs. Then in the Read method, you can increment your volume multiplier by the desired delta for every sample, allowing a smooth fade.

Mark

Oct 12, 2009 at 6:11 PM

Hi Mark,

Can you elaborate on your described solution?  I would like to use NAudio to set the volume level at any level at any time in the file, so i can fade up and down at will throughout.

I am very new to audio management in c# and am not sure how to start.

Thanks for any input.

Jason

Coordinator
Oct 12, 2009 at 6:27 PM

Hi Jason,

in a fadeout, you move the volume from 1 to 0 over a set period of time. This means that you need to do a bit of maths. Work out how many samples are in your fade-out time. This lets you work out a "delta" - the amount to reduce the volume by each sample.

I've put this on my list of things to blog about, so maybe there will be an example for you at some point.

Mark

Oct 12, 2009 at 6:54 PM
Edited Oct 12, 2009 at 6:58 PM

Hi Mark, Thanks for your reply,

The only question I have then, is how do I break a wave file down to iterate through the samples, and set the volume on that sample before writing out to the new wave file?  In other words, what classes provide this functionality?

Right now I am using the following code to open a file and then save it at a new rate:

            string inFile = @"path to in file";
            string outFile = @"path to out file";
            using (WaveFileReader reader = new WaveFileReader(inFile))
            {
                WaveFormat of = new WaveFormat(48000, 16, 2);
                using (ResamplerDmoStream rso = new ResamplerDmoStream(reader, of)){
                    using (WaveFileWriter wri = new WaveFileWriter(outFile, of))
                    {
                        byte[] buffer = new byte[1024];
                        int bytesRead; 
                        do{
                            bytesRead = rso.Read(buffer, 0, buffer.Length);
                            wri.WriteData(buffer, 0, bytesRead);
                        }while(bytesRead > 0);

                    }
                }
            }

I would assume that somewhere in that do while, I should be able to tweak the volume? Or am I way over simplifying this.

Thanks

jason 

Coordinator
Oct 12, 2009 at 7:41 PM

well to tweak the volume you need to turn every pair of bytes you read into an Int16, multiply by the volume, then turn it back into bytes again to write to the file.

In NAudio, you would typically do this by creating a new WaveStream derived class that would do the volume adjustment for you, and passing it the ResamplerDmoStream as an input.

Oct 12, 2009 at 7:44 PM

Even though this is a support forum for NAudio, I would like to present my solution. I used http://sox.sourceforge.net/ which has all the most common things already developed and tested!

Oct 12, 2009 at 8:41 PM

Update :

This code successfully re-encodes my wave file at 10% volume! Thanks for the poke in the right direction Mark.

I am now trying to wrap my head around timing, so if I want to change the volume at the 01:10:12 mark (one minute, 10 second, 12th frame) how does that equate in this byte array? can I just divide the duration of the wave file by the total bytes then divide by 30 (for 30 fps) to get the number of bytes per frame?

        static void Main()
        {
            string inFile = @"C:\Users\Jason\Desktop\test.wav";
            string outFile = @"C:\Users\Jason\Desktop\sup.wav";
            using (WaveFileReader reader = new WaveFileReader(inFile))
            {
                WaveFormat of = new WaveFormat(48000, 16, 2);
                using (ResamplerDmoStream rso = new ResamplerDmoStream(reader, of)){
                    using (WaveFileWriter wri = new WaveFileWriter(outFile, of))
                    {
                        byte[] buffer = new byte[1024];
                        int bytesRead;
                        int count = 0;
                        do{
                            bytesRead = rso.Read(buffer, 0, buffer.Length);
                            for (int j = 0; j < buffer.Length; j+=2)
                            {
                                count++;
                                short snd = ComplementToSigned(ref buffer, j);
                                snd = (short)(snd * .1);
                                byte[] changed = SignedToComplement(snd);
                                if ((changed[0] != null) && (changed[1] != null))
                                {
                                    buffer[j] = changed[0];
                                    buffer[j + 1] = changed[1];
                                }
                            }
                            wri.WriteData(buffer, 0, bytesRead);
                        }while(bytesRead > 0);
                        Console.WriteLine(count.ToString());

                    }
                }
            }
        }

        private static short ComplementToSigned(ref byte[] bytArr, int intPos)
        {
            short snd = BitConverter.ToInt16(bytArr, intPos);
            if (snd != 0)
                snd = Convert.ToInt16((~snd | 1));
            return snd;
        }
        private static byte[] SignedToComplement(short shtVal) //Convert to 2's complement and return as byte array of 2 bytes
        {
            byte[] bt = new byte[2];
            shtVal = Convert.ToInt16((~shtVal | 1));
            bt = BitConverter.GetBytes(shtVal);
            return bt;
        }
Coordinator
Oct 12, 2009 at 8:49 PM

frames per second is for video. audio is samples per second, and you have 48000 samples per second in your code above. Also, you are using stereo, so you actually have 96000 samples per second (48000 pairs). From that you can work out how many samples before your target time.

 

Oct 12, 2009 at 9:17 PM

Thank you mark for your help!

I really appreciate it, I think I have enough to go on for now!

Jason

Mar 29, 2010 at 11:34 AM

this code's useful to me.

but I'll apreciate if You help me this.

I want to fade first 2s out.

like this

mp3 waveform:

  ------------------------

 -                              -

-                                -

It'll easier for listener.

Coordinator
Mar 29, 2010 at 3:25 PM

to do fades you need first to convert to PCM. Then you need to create your own algorithm for adjusting the volume of each sample (whether a linear or exponential fade). NAudio does not do this for you I'm afraid. One day I'll try to get round to blogging about how to do this.

Mark

 

Mar 30, 2010 at 1:50 AM

Thank you for your respond, Mark.

I'm New but I'll try.

Dec 21, 2011 at 2:45 AM

Mark, ever get around to blogging about this? :)

Coordinator
Dec 21, 2011 at 10:35 AM

hi I'm afraid not so far, but with the new ISampleProvider interface in NAudio 1.5 it will become much easier to implement as you won't have to worry about bit conversion.

Mark