Question

.......
.......

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)?

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top