G.727 Support

Nov 7, 2012 at 9:30 AM

Hello Mark,

I'd like to use NAudio to play 5-, 4-, 3- and 2-bit/sample ADPCM (G.727), but as far as I see G.727 is not supported. Am I wrong with that assumption? Do you see any chance to play that files?


Best regards

Karsten


 

Coordinator
Nov 7, 2012 at 9:33 AM

NAudio can use any ACM codec installed on your system. So if you have a G.727 ACM codec, you will be able to use it to decompress the audio. You would also need to create a WaveFormat with exactly the right parameters for the codec to pick it up.

Nov 7, 2012 at 1:24 PM

Hi Mark,

thank you for your fast reply.

I don't have a G.727 ACM codec installed, but me collegue gave me a dll where I can call a function to convert from G.727 to ALaw.

The last hours I tried to write G727WaveStream which inherits WaveStream. In its Read() method I do the convertion. Unfortunately that does not work yet. Is the choosen path right or do I have to try a different approach?


Ciao

Karsten

 

Coordinator
Nov 7, 2012 at 2:22 PM

Yes, that is a reasonable enough solution. WaveStream is a bit more complex to implement than IWaveProvider as it also suports repositioning

Nov 7, 2012 at 3:49 PM

Actually I need repositioning, but that task comes later. For now I would be happy if I understood, how to provide the correct settings to play that adpcm data.

My G727WaveStream provides a WaveFormat which reflects the converted data (ALaw). That should be playable, but WaveOut.Init(g727WaveStream) throws "WaveBadFormat calling waveOutOpen".

I have tried ALL formats, but all I got is the WaveBadFormat exception. Only when I use Pcm as encoding I don't get that exception, but the dll call hangs.

You said the way is correct, so I don't understand what's the problem.

 

Coordinator
Nov 7, 2012 at 4:00 PM

You'll still need to use WaveFormatConversionStream.CreatePcmStream to go to PCM before you try playing.

Nov 12, 2012 at 3:05 PM

Thank you very much. Your statements were very helpful. I had some problems calling the ADPCM.dll properly. But now it seems to work mostly.

Unfortunately only mostly, because the library proccesses the G.727 data only in 512 byte blocks. This results in the following ALaw block sizes:

2-bit: 2048 bytes
3-bit: 1365 bytes
4-bit: 1024 bytes
5-bit: 819 bytes

The Read() method asks for a 2880 byte buffer to be filled. If I use 4-bit samples I process two blocks, fill 2048 bytes and return this 2048. But then the next Read() call asks for the remaining 832 bytes which are less than the library can process.

That leaves me with two possibilities:
1.) Regulate NAudio to ask for the right buffer size
2.) Process three blocks, fill exactly 2880 bytes and buffer the remaining 192 bytes for the next time

Is 1.) possible?

Best wishes

Coordinator
Nov 12, 2012 at 3:39 PM

WaveFormatConversionStream should use the BlockAlign parameter of the source stream to manage its read sizes. Make sure that is set to the correct block size.

Mark

Nov 12, 2012 at 3:47 PM

As far as I understand BlockAlign should be 0.5...



However I will try different BlockAlignments affect the buffer size.

 

Thank you

 

Coordinator
Nov 12, 2012 at 3:57 PM

No, BlockAlign is the number of bytes that must be read together. If you want to read blocks of 819 bytes, then BlockAlign should be 819

Nov 12, 2012 at 4:06 PM

Now I understand! With a block align of 2048 I can process the blocks seemlessy now. Unfortunately that didn't fix the stumbling I experience. I will try further and keep you up to date.

Ciao

Nov 13, 2012 at 11:07 AM

Hi Mark,

it seems that BlockAlign needs to be a divisor of 2880. Otherwise I get the mentioned stumbling. I will put up a minimalistic example...


Bye

Nov 13, 2012 at 11:24 AM
private static void Test()
{
	WaveFormatEncoding tag = WaveFormatEncoding.ALaw;
	int sampleRate = 19200;
	int channels = 1;
	int bitsPerSample = 8;
	int blockAlign = 1024; // (channels * bitsPerSample) / 8;
	int averageBytesPerSecond = (sampleRate * channels * bitsPerSample) / 8;
	WaveFormat format = WaveFormat.CreateCustomFormat(tag, sampleRate, channels, averageBytesPerSecond, blockAlign, bitsPerSample);

	string filename = @"C:\Alaw_1Channel_8Bit_19200SamplesPerSec.asf";
	FileStream filestream = new FileStream(filename, FileMode.Open);
	RawSourceWaveStream alawStream = new RawSourceWaveStream(filestream, format);
	WaveStream waveStream = WaveFormatConversionStream.CreatePcmStream(alawStream);
	IWavePlayer wavePlayer = new WaveOut();

	wavePlayer.Init(waveStream);
	wavePlayer.Play();

	MessageBox.Show("Playing...");

	wavePlayer.Stop();
	wavePlayer.Dispose();
	waveStream.Close();
	alawStream.Close();
	filestream.Close();
}

Coordinator
Nov 13, 2012 at 11:45 AM

That is very odd, because blockAlign should be 1 for A-law. You can decompress each sample individually.

Also, 19200 samples per second is a very odd wave sampling rate, and I'd be surprised if your soundcard plays it correctly.

Nov 14, 2012 at 8:19 AM

Hi Mark,

I fully agree that BlockAlign for A-law should be 1. But as far as I can see, it can be greater. In this short example I wanted to show what happens, if you use a BlockAlign 1024, which I use.

I experience the same stumbling when I use a file with a SampleRate of 24000.

 

Nov 15, 2012 at 1:37 PM

Hi Mark,

do you think it is a calibration thing, or do you suggest to solve it differently?

 

Coordinator
Nov 16, 2012 at 11:17 AM

I'm not sure what you mean by "stumbling". 24000 is also possibly not suppored by all soundcards. 22050 is more likely.

Nov 16, 2012 at 12:44 PM

Hi Mark,

I have PCM, aLaw and ADPCM2, 3, 4 & 5 data with sample rates of 8000, 12000, 16000 and 19200.
For PCM and aLaw also 24000. My soundcard had never a problem with any of these sample rates. When I provided a wrong sample rate on purpose, it played it slowlier or faster.

Have you tried the example? Of course you have to use the sample rate of your file.

But please ignore this if you are busy. Today I solved that issue by providing exactly 2880 bytes. The rest is buffered for the next Read call. Now I have no problems.


Best regards

Karsten

Coordinator
Nov 17, 2012 at 9:00 AM

You can try wrapping your waveformatconversionstream in a blockalignreductionstream before passing it to waveout, which might help. I still can't understand why you'd need to change blockalign for a-law. I use a-law all the time with NAudio and have never needed to do that. Your file has an asf extension, which suggests to me that there is more than just raw audio in the file.

As for sample rates, I suspect that windows is using another WaveFormatConversionStream under the hood to do SRC on the fly. This might account for some of the issues you have.

Nov 19, 2012 at 8:18 AM

Hi Mark,

I am very thankful for all code and help you provided. Since thursday I am able to play that data flawlessly. So please understand that when we talk about that issue it is not to help me, but to improve NAudio. Let's not talk about my files, sample rates or headers. I want to inform you that I hear stumbling if I use a block align which is not a divider of 2880 (1024 for example). You may use this information or not, it is your choice.


Bye