Resample problem

Mar 5, 2012 at 9:59 PM

When I'm trying to resample IeeeFloat wave format with sample rate of 48000 to wave format with sample rate of 41000, an exception occurred - "AcmNotPossible calling acmStreamOpen".

What is the right way to convert an input stream from one wave format to another. I need to feed MixingSampleProvider with two streams with equal wave formats.

Coordinator
Mar 5, 2012 at 10:02 PM

Are they both IEEE float? And do they both have the same number of channels? I can't remember off the top of my head if the ACM resampler can do IEEE. There is also the DmoResampler available on Vista and Win 7 if not. I've also got a fully managed resampler in the works but its not ready yet

Mark

Mar 6, 2012 at 11:00 AM

They are both IEEE float. The number of channels is equal - 2. Maybe I have to convert them first to 16bit PCM and then resample?

Coordinator
Mar 6, 2012 at 11:04 AM

yes, you might have to to use the ACM resampler.

Mar 6, 2012 at 7:50 PM
Edited Mar 6, 2012 at 7:51 PM

If I use

WaveFormat waveFormat = new WaveFormat(44100, 2); 
mixer = new MixingSampleProvider(waveFormat);

everything is ok with the WaveFormatConversionStream. But then I'm trying to save mixed song to the disk like this

WaveFileWriter.CreateWaveFile(mixedSong, new SampleToWaveProvider(mixer));

I recieve error: "Must be already floating point".

Coordinator
Mar 7, 2012 at 4:07 PM

How did you manage to create MixingSampleProvider with that WaveFormat? It should have thrown an exception

Mar 7, 2012 at 4:58 PM

What kind of exception. The constructor overload of MixingSampleProvider with WaveFormat is so simple. Why it should throw any exception?

If I use:

WaveFormat waveFormat = WaveFormat.CreateIeeeFloatWaveFormat(44100, 2);

Then the problem I have mentionied earlier occurred - I cannot resample the input streams with that IEEE format.

Coordinator
Mar 7, 2012 at 5:26 PM

maybe I added that in a later version. all SampleProviders must be IEEE float. they will not work with PCM audio

Mar 9, 2012 at 7:03 PM

So what is the best way to mix two ISampleProvider streams with different wave formats. Especially waveIn stream and a converted to wave MP3 stream.

I have to provide IEEE float wave format that actually cannot be resampled. I'm stuck...

Coordinator
Mar 10, 2012 at 8:38 AM

Yes, the WaveFormatConversionStream cannot resample IEEE. You either have to use the DmoResampler, or convert first to 16 bit PCM, resample, and then go back to IEEE. I am working on a fully managed resampler, but it is not ready to be incorporated into NAudio yet.

Mark

Mar 10, 2012 at 9:29 PM
Now I'm able to do the mixing like this:
WaveFormat waveFormat = new WaveFormat(44100, 2);
WaveFileReader reader = new WaveFileReader(fileName);
WaveFormatConversionStream convertStream = new WaveFormatConversionStream(waveFormat, reader);
cm16BitToSampleProvider sampleProvider = new Pcm16BitToSampleProvider(convertStream);
mixer.AddMixerInput(sampleProvider);

But how can I play/save the mixer stream. The problem is that it is 16bit PCM at this stage and I need to convert it to IWaveProvider

 

Coordinator
Mar 11, 2012 at 5:42 PM

if it is a sampleprovider then it is IEEE float. That  is what Pcm16BitToSampleProvider does

Mar 11, 2012 at 6:13 PM

The mixer itself is 16bit PCM. Pcm16BitToSampleProvider needs IWaveProvider as source. Mixer is ISampleProvider. If I convert it using SampleToWaveProvider it tells me that must be floating point...

Coordinator
Mar 11, 2012 at 7:29 PM

The WaveFormat of your sampleProvider class should be IEEE. Please do a sampleProvider.WaveFormat.ToString() and tell me what you've got.

You can go back fom ISampleProvider to IWaveProvider using SampleToWaveProvider in order to play the audio. (n.b. in the very latest code there is SampleToWaveProvider16, which will also put it back to 16 bit PCM).

Mar 11, 2012 at 7:44 PM

sampleProvider.WaveFormat.ToString() - "IeeeFloat"

mixer.WaveFormat.ToString()  -"16 bit PCM: 44kHz 2 channels"

I need to play the mixer that is 16 bit PCM...

Coordinator
Mar 11, 2012 at 7:53 PM

If you are using MixingSampleProvider you must pass in an IEEE format into its constructor. The bug that lets you pass in PCM was fixed last month. It simply will not work with PCM, even though the version you are using lets you pass in the wrong WaveFormat.

Mar 11, 2012 at 8:01 PM
Edited Mar 11, 2012 at 8:03 PM

But when I pass this waveFormat instance

WaveFormat waveFormat = WaveFormat.CreateIeeeFloatWaveFormat(44100, 2);

the following line throws exception:

WaveFormatConversionStream convertStream = new WaveFormatConversionStream(waveFormat, reader);

"AcmNotPossible calling acmStreamOpen". That's the issue that I'm trying to resolve.

Jan 15, 2014 at 2:55 PM
Has anybody figured out the solution? I have the exact same problem. just cannot convert the PCM wav to IEEE wave format in any way. I believe I do have the needed codecs. Thank you for any hint or help!
Jan 16, 2014 at 12:05 PM
Edited Jan 16, 2014 at 12:13 PM
The SampleProvider classes in the NAudio source contains float[] to byte[] conversion code.

I based this function on the code in NAudio as a quick conversion function.
It works fine but I haven't fully tested it in all scenario's.
It takes an OffsetSampleProvider but you can easily change it to another SampleProvider that uses the standard Read functions, or a raw float array if need be.

(Due to a forum formatting glitch change PLUS PLUS to the symbol plus plus)
    // float samples to stream as byte buffer
    void SampleProviderToByteBuffer(OffsetSampleProvider oSP, Stream streamOutput)
    {
        int nReadF = 0;
        float[] bufferF = new float[1024];
        byte[] bufferB = new byte[2048];
        WaveBuffer destWaveBuffer = new WaveBuffer(bufferB);
        int destOffset = 0;
        float volume = 1;
        do
        {
            destOffset = 0;
            nReadF = oSP.Read(bufferF, 0, bufferF.Length);
            for(int n=0;n<bufferF.Length;n PLUS PLUS)  //  (HTML FORMATTING GLITCH)
            {

                // adjust volume
                float sample32 = bufferF[n] * volume;
                // clip
                if (sample32 > 1.0f)
                    sample32 = 1.0f;
                if (sample32 < -1.0f)
                    sample32 = -1.0f;

                destWaveBuffer.ShortBuffer[destOffset PLUS PLUS] = (short)(sample32 * 32767);   



            }

            streamOutput.Write(bufferB, 0, nReadF*2);
            destWaveBuffer.Clear();
        }
        while(nReadF > 0);

    }
Coordinator
Jan 16, 2014 at 12:11 PM
Use the .ToSampleProvider() extension method to go from 16 bit PCM to an IEEE float ISampleProvider. Under the hood it simply calls this:
SampleProviderConverters.ConvertWaveProviderIntoSampleProvider(waveProvider);

No need for WaveFormatConversionStream
Jan 16, 2014 at 12:57 PM
I put together that function due to issues with WaveStream -> ToSampleProvider() -> OffsetSampleProvider -> MFEncoder, for some reason the output file was the full length of the input file depending on what MF codec I selected. Not sure if its an issue with the codecs themselves or MF or NAudio but either way I ended up splitting the whole process into two steps to avoid complex situations.
  1. Convert the input file to a WAV file.
  2. Convert the WAV file to the target format.