This project has moved. For the latest updates, please go here.

Problem Converting To GSM610

Feb 3, 2012 at 11:02 AM

I've been trying in my application to convert a PCM file to GSM610 format using the following error.

"AcmNotPossible calling acmStreamOpen"

I had a look though the earlier discussion and its been suggested to try it though the demo applicaiton. Howerver using the demo applicaiton im getting the same error.

I can confirm that I have it installed on my system. i can see the codec looking at them though windows media player technical information.

Please advise?

Thanks

Coordinator
Feb 3, 2012 at 11:07 AM

not all conversions can be performed in one step. Probably it is the sample rate. Try downsampling to 8kHz PCM first.

Feb 3, 2012 at 11:30 AM

thanks for the fast reply.

 

I've just gone though using the demo app converting it to all the pcm options then trying to converter them to gsm610.

 

I can the same error for all of them

Coordinator
Feb 3, 2012 at 11:32 AM

what exactly is the format of the file you are trying to convert to GSM? It probably needs to be mono, 8kHz, 16 bit

Feb 3, 2012 at 12:20 PM

I'm trying from mono 8khz 16bit to GSM 6.10 8khz mono

Coordinator
Feb 6, 2012 at 12:41 PM

that should work, can you post a code snippet of your call into WaveFormatConversionStream?

Feb 23, 2012 at 1:00 PM

here you go

using (WaveFileReader reader = new WaveFileReader(Input))
            {
                using (WaveFormatConversionStream Conveter = new WaveFormatConversionStream(WaveFormat.CreateCustomFormat(WaveFormatEncoding.Gsm610, 8000,
                    116000216), reader))
                {
                    WaveFileWriter.CreateWaveFile(Output, Conveter);
                }
            }
Coordinator
Feb 23, 2012 at 1:12 PM

try using Gsm610WaveFormat instead:

using (WaveFileReader reader = new WaveFileReader(Input))
{
    using (var Conveter = new WaveFormatConversionStream(new Gsm610WaveFormat()), reader))
    {
        WaveFileWriter.CreateWaveFile(Output, Conveter);
    }
}

Feb 23, 2012 at 2:16 PM

i get a slightly different error doing that.

AcmNotPossible calling acmStreamSize   

at NAudio.MmException.Try(MmResult result, String function)   

at NAudio.Wave.Compression.AcmStream.SourceToDest(Int32 source) 

 at NAudio.Wave.WaveFormatConversionStream.SourceToDest(Int32 source)   

at NAudio.Wave.WaveFormatConversionStream..ctor(WaveFormat targetFormat, WaveStream sourceStream)

Coordinator
Feb 26, 2012 at 3:55 PM

you'll need to do your own loop to use buffer sizes that are multiples of GSM block align. Look in the ssource for the code to WaveFileWriter.CreateWaveFile - it is only a few lines of code.

Mar 5, 2012 at 1:49 PM

I don't suppose you could shed a little more light on this please?  I'm trying to do the same PCM to GSM conversion and get exactly the same error.

From what I can gather, the issue is with moving from a block align of 2 to 65, but I don't know how to deal with this.  Do I need to create a new class deriving from WaveStream to pass to the conversion stream? 

My ultimate goal is to insert a period of silence into a GSM file, so what I'm doing is converting to PCM, inserting the appropriate empty bytes and then converting back to GSM.  Is there a better way to do this?

Thanks,
Chris

Coordinator
Mar 5, 2012 at 1:55 PM

Here is the full source code for CreateWaveFile:

        public static void CreateWaveFile(string filename, IWaveProvider sourceProvider)
        {
            using (WaveFileWriter writer = new WaveFileWriter(filename, sourceProvider.WaveFormat))
            {
                byte[] buffer = new byte[sourceProvider.WaveFormat.AverageBytesPerSecond * 4];
                while (true)
                {
                    int bytesRead = sourceProvider.Read(buffer, 0, buffer.Length);
                    if (bytesRead == 0)
                        break;
                    writer.Write(buffer, 0, bytesRead);
                }
            }
        }

The problem is simply that the size of the buffer ought to be a multiple of 65. Make it 65000 or something. Then it should work.

As for how to insert silence, your way is fine. The only alternative is to create one 65 byte block of GSM silence (don't know what that looks like), and insert those blocks. However, even that may produce artefacts if the GSM codec stores state between consecutive blocks.

Mar 5, 2012 at 2:40 PM

Thanks for the quick reply.

Where should I be calling that code then?  Trying the example you posted in reply to jonny, I get the exception when initialising the conversion stream.  It doesn't ever get as far as calling CreateWaveFile.

Coordinator
Mar 5, 2012 at 2:45 PM

OK, are you definitely using the Gsm610WaveFormat class?

Also, before you can go to GSM 610, you already need to have resampled to 8kHz, if your audio was originally at a higher sample rate

Mar 5, 2012 at 3:57 PM

Yes, I'm using the Gsm610WaveFormat class and I've already ensured the PCM is at 8kHz.

I've also tried generating the PCM file myself so that I know it's at the correct sample rate.  Should the following work?

 

string pcmFilepath = @"D:\Temp\GeneratedPCM.wav";
string gsmFilepath = @"D:\Temp\ConvertedGSM.wav";

int sampleRate = 8000;
WaveFormat pcmFormat = new WaveFormat(sampleRate, 16, 1);

// Generate 8 kHz PCM audio:
using (WaveFileWriter pcmWriter = new WaveFileWriter(pcmFilepath, pcmFormat))
{
   int frequency = 440;
   short amplitude = 10000;
   int duration = 2;
   double omega = frequency * 2 * Math.PI / sampleRate;

   short[] buffer = new short[100];
   int bufferPos = 0;

   for (int i = 0; i < sampleRate * duration; i++)
   {
       short sample = (short)(amplitude * Math.Sin((double)i * omega));
       buffer.SetValue(sample, bufferPos);
       bufferPos++;

       if (bufferPos == buffer.Length)
       {
           pcmWriter.WriteSamples(buffer, 0, buffer.Length);
           bufferPos = 0;
       }
   }
}

// Convert to GSM:
using (WaveFileReader reader = new WaveFileReader(pcmFilepath))
{
   using (WaveFormatConversionStream converter = new WaveFormatConversionStream(new Gsm610WaveFormat(), reader))
   {
       WaveFileWriter.CreateWaveFile(gsmFilepath, converter);
   }
}

Thanks for helping by the way!

Coordinator
Mar 5, 2012 at 4:06 PM

there is an ACM demo in the NAudioDemo app that will tell you what ACM codecs you have installed on your system. Check that there is actually a GSM one there. What version of Windows are you running on?

Mar 5, 2012 at 4:24 PM

I've tried that and I can see the corresponding entry for the GSM format I'm trying to convert to:

===========================================
Format Tag 1: GSM 6.10
   Standard Format Count: 4
   Support Flags: Codec
   Format Tag: Gsm610, Format Size: 20
   Formats:
   ===========================================

.....

   Format 0: 8.000 kHz, Mono
      FormatTag: Gsm610, Support Flags: Codec
      WaveFormat: Gsm610 8000Hz Channels: 1 Bits: 0 Block Align: 65, AverageBytesPerSecond: 1625 (13.0 kbps), Extra Size: 2
   ===========================================

 

I'm running Windows 7 Pro, 32-bit.  If it makes any difference, I can save as GSM using GoldWave audio editor.

Coordinator
Mar 5, 2012 at 4:26 PM

Can you convert your PCM file using the Encode button in the NAudioDemo app?

Mar 5, 2012 at 4:32 PM

Nope.  I get the same "AcmNotPossible calling acmStreamSize" error.

Coordinator
Mar 5, 2012 at 4:34 PM

and that is in the WaveFormatConversionStream constructor? or in CreateWaveFile?

Mar 5, 2012 at 4:39 PM

That's in the constructor again.

Stack trace:

at NAudio.MmException.Try(MmResult result, String function) in D:\\VS Projects\\NAudio 1.5\\NAudio\\Wave\\MmeInterop\\MmException.cs:line 39
at NAudio.Wave.Compression.AcmStream.SourceToDest(Int32 source) in D:\\VS Projects\\NAudio 1.5\\NAudio\\Wave\\Compression\\AcmStream.cs:line 75
at NAudio.Wave.WaveFormatConversionStream.SourceToDest(Int32 source) in D:\\VS Projects\\NAudio 1.5\\NAudio\\Wave\\WaveStreams\\WaveFormatConversionStream.cs:line 55
at NAudio.Wave.WaveFormatConversionStream..ctor(WaveFormat targetFormat, WaveStream sourceStream) in D:\\VS Projects\\NAudio 1.5\\NAudio\\Wave\\WaveStreams\\WaveFormatConversionStream.cs:line 46
at NAudioDemo.AcmPanel.EncodeFile() in D:\\VS Projects\\NAudio 1.5\\NAudioDemo\\AcmDemo\\AcmPanel.cs:line 126
at NAudioDemo.AcmPanel.buttonEncode_Click(Object sender, EventArgs args) in D:\\VS Projects\\NAudio 1.5\\NAudioDemo\\AcmDemo\\AcmPanel.cs:line 33"

Coordinator
Mar 5, 2012 at 4:48 PM

OK, will have to try to debug this one myself. I suspect sending in non block aligned values is confusing it

Coordinator
Mar 5, 2012 at 8:43 PM

OK, fixed the bug and checked in this evening. You can build your own copy of NAudio, or if you know how to use NuGet to get a pre-release version, you can get it from the NuGet gallery:

https://nuget.org/packages/NAudio/1.5.3-beta

Mar 6, 2012 at 10:11 AM

That's fantastic, thanks! 

Works a charm.