0
.......
.......

var mixer = new WaveMixerStream32();
mixer.AutoStop = true;

var messageOffset = background.TotalTime;
var messageOffsetted = new WaveOffsetStream(message, 
                                         TimeSpan.FromSeconds(10), 
                                         TimeSpan.Zero,message.TotalTime.Subtract(TimeSpan.FromSeconds(10)));             

var background32 = new WaveChannel32(background);
background32.PadWithZeroes = false;
background32.Volume = 0.6f;               
mixer.AddInputStream(background32);

var message32 = new WaveChannel32(messageOffsetted);
message32.PadWithZeroes = false;
message32.Volume = 0.3f;
mixer.AddInputStream(message32);

var ws = new Wave32To16Stream(mixer);

We are trying to mix multiple mp3's and wave files to create a single MP3 finally.

Example: 5 sources files (3 mp3's, 2 wave files)

We are giving input of each stream to WaveMixerStream32 and finally converting it using Wave32To16Stream

We need this final stream to be converted to MP3. For this we are using LAME and passing the stream to EncodeMixedStreamAsMp3 which is returning an error "Invalid file format".

After researching, we found that RIFF header is missing in the mixed wave stream.

How to add a RIFF to a mixed wave stream which is generated based on multiple sources (MP3 and WAVE)?

sainath sagar
  • 499
  • 2
  • 10
  • 28

1 Answers1

1

An NAudio WaveStream is a stream of sample data with a specified format, not a RIFF WAV file as expected by LAME. To convert it to a RIFF WAV file you need to add RIFF headers and so on. The NAudio.Wave.WaveFileWriter class does this.

If you're working with smallish output files that aren't going to blow your memory, you can do something simple like (assuming Yeti's LAME wrapper or similar):

(code updated 19-Aug-2013):

public byte[] EncodeMP3(IWaveProvider ws, uint bitrate = 128)
{
    // Setup encoder configuration
    WaveLib.WaveFormat fmt = new WaveLib.WaveFormat(ws.WaveFormat.SampleRate, ws.WaveFormat.BitsPerSample, ws.WaveFormat.Channels);
    Yeti.Lame.BE_CONFIG beconf = new Yeti.Lame.BE_CONFIG(fmt, bitrate);

    // Encode WAV to MP3
    int blen = ws.WaveFormat.AverageBytesPerSecond;
    byte[] buffer = new byte[blen];
    byte[] mp3data = null;

    using (MemoryStream mp3strm = new MemoryStream())
    using (Mp3Writer mp3wri = new Mp3Writer(mp3strm, fmt, beconf))
    {
        int rc;
        while ((rc = ws.Read(buffer, 0, blen)) > 0)
            mp3wri.Write(buffer, 0, rc);
        mp3data = mp3strm.ToArray();
    }
    return mp3data;
}

-- Update: Setting MP3 encoding parameters

Using the Yeti LAME wrapper, you can specify the MP3 encoding parameters by passing in a BE_CONFIG structure like so:

WaveLib.WaveFormat fmt = new WaveLib.WaveFormat(ws.WaveFormat.SampleRate, ws.WaveFormat.BitsPerSample, ws.WaveFormat.Channels);

Yeti.Lame.BE_CONFIG beconf = new Yeti.Lame.BE_CONFIG(fmt, 64);
using (MemoryStream mp3strm = new MemoryStream())
using (Mp3Writer mp3wri = new Mp3Writer(mp3strm, fmt, beconf))
{
...
}

The BE_CONFIG constructor takes a WaveLib.WaveFormat and an optional CBR bit rate in Kb/s. If you don't specify a bit rate it defaults to 128Kb/s output. If you don't supply the configuration to the Mp3Writer it creates a default one from the WaveFormat.

The code above creates a BE_CONFIG with the output rate set to 64Kb/s. If you want a different bit rate, just specify it in place of the 64 in new Yeti.Lame.BE_CONFIG(fmt, 64);

BE_CONFIG contains a lot of other options, most of which you won't ever use. Check out the (slightly sketchy) documentation here.

Corey
  • 15,524
  • 2
  • 35
  • 68
  • Hi @Corey, I have one more query. I am able to get mp3 output which is 128 kbps bit rate. Now I want the output to be in 64 kbps. Is there any way to do it. I googled about it but i hardly find any solution. – sainath sagar Aug 12 '13 at 09:54
  • You need to setup the Mp3Writer with the right configuration. I'll add some code... – Corey Aug 13 '13 at 01:47
  • Hi @Corey, your code is working fine with mp3 and wave streams but when i used ogg stream with the help of NVorbis.NAudioSupport.VorbisWaveReader in your function i am getting noise output with song playing slowly which is also not clear at all.Please, correct me where i am going wrong.I have used 16 bits per sample in WaveLib.WaveFormat as my ogg was giving 32 bits per sample. – sainath sagar Aug 14 '13 at 07:47
  • @sainathsagar You need to convert all of your inputs to the same format before mixing them, so your decoded ogg needs to be converted to 16 bit. `VorbisWaveReader` is a `WaveStream` you can use the `NAudio.Wave.Wave32To16Stream` to wrap it, giving you a 16-bit `WaveStream` to encode. – Corey Aug 14 '13 at 22:29
  • @sainathsagar Oh, it's not 32-bit PCM, it's 32-bit Float. `Wave32To16Stream` won't cut it, you'll need to convert the floating-point samples to 16-bit PCM samples with `NAudio.Wave.SampleProviders.SampleToWaveProvider16`. – Corey Aug 14 '13 at 23:09
  • SampleToWaveProvider16 samp = new SampleToWaveProvider16(sws); var pcm = new NAudio.Wave.SampleProviders.WaveToSampleProvider(samp); Here, when i am trying to use CopyTo(memorystreamobject),it is giving me error. I think we need to convert to wave stream. but i hardly find any function that converts sampleprovider to wavestream in NAudio. Please,correct me where i am going wrong. – sainath sagar Aug 16 '13 at 08:15
  • Sorry, Here is the code which i am using. var sws = new NVorbis.NAudioSupport.VorbisWaveReader(ms); SampleToWaveProvider16 samp = new SampleToWaveProvider16(sws); – sainath sagar Aug 16 '13 at 08:22
  • See modified `EncodeMP3` code above. Changed to use `IWaveProvider` instead of `WaveStream`. Since `WaveStream` implements `IWaveProvider` you can pass either in to the new code. – Corey Aug 18 '13 at 23:22
  • Hi @Corey, here with your above code output which i am getting is not so clear and also the size of the file also not decreased compare to the output which i got from audacity software. I dnt know what code they are using to do so. – sainath sagar Aug 20 '13 at 05:49