Author Topic: convert alaw to linear pcm  (Read 119 times)

jakob

  • Posts: 137
convert alaw to linear pcm
« on: 26 May '21 - 12:36 »
hi
I am trying to figure out how to convert telephony audio to regular pcm audio and back.
The input format is G711 alaw 8 kHz 8 bit and I want the output to be linear pcm 16 kHz 16 bit.
the input audio is streamed, so it is not coming from a file.

I have looked at BASS_Encode_StartACM, but as fare as I can see, that is only an option if I want to encode to alaw.

Is there a way to do this both ways and also not from a recorder?

Ian @ un4seen

  • Administrator
  • Posts: 23619
Re: convert alaw to linear pcm
« Reply #1 on: 26 May '21 - 15:26 »
BASS can decode alaw data (with the help of ACM) but it will need to see a WAVE header to detect the format. If you currently have raw headerless data, perhaps you could put a WAVE header in front of the data and pass that to BASS_StreamCreateFile. You can do that all in memory (no need to write a file) and set mem=TRUE in the BASS_StreamCreateFile call. The header's "fmt " chunk would look like this:

Code: [Select]
WAVEFORMATEX fmt;
fmt.wFormatTag = WAVE_FORMAT_ALAW;
fmt.nChannels = 1;
fmt.nSamplesPerSec = 8000;
fmt.nAvgBytesPerSec = 8000;
fmt.nBlockAlign = 1;
fmt.wBitsPerSample = 8;
fmt.cbSize = 0;

Alternatively, you could decode the alaw data yourself. There is public domain source code available for that (search for "g711.c").

jakob

  • Posts: 137
Re: convert alaw to linear pcm
« Reply #2 on: 26 May '21 - 15:38 »
hi Ian
Thank you
Using C# I think I will go down the road of generating a wav header.
I don't think g711.c comes in a managed version

when generating alaw i call BASS_Encode_GetACMFormatSuggest to get the codec. but this does not have an option in BASSACMFormat or WAVEFormatTag for alaw or g711 even.
also looking at the ACM available in windows i have G711 alaw and ulaw as a single codec. but how do i specify alaw rather than ulaw when calling BASS_Encode_StartACM
What do you suggest here?
« Last Edit: 26 May '21 - 15:44 by jakob »

Ian @ un4seen

  • Administrator
  • Posts: 23619
Re: convert alaw to linear pcm
« Reply #3 on: 26 May '21 - 16:45 »
WAVE_FORMAT_ALAW is defined as 6, so you could try using that number in your BASS_Encode_GetACMFormatSuggest call "format" parameter.

jakob

  • Posts: 137
Re: convert alaw to linear pcm
« Reply #4 on: 8 Jun '21 - 15:14 »
hi
I have tried to test the decoding of alaw using BASS. Basically I have a wave file with alaw data that I load into memory and feed the decoder.
I tried the following:
m_DecodingStream = Bass.BASS_StreamCreate(8000, 1, BASSFlag.BASS_STREAM_DECODE, BASSStreamProc.STREAMPROC_PUSH);
m_Stream = BassMix.BASS_Mixer_StreamCreate(16000, 1, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MIXER_END);
BassMix.BASS_Mixer_StreamAddChannel(m_Stream, m_DecodingStream, BASSFlag.BASS_DEFAULT);

putting alaw data into the decoder with Bass.BASS_StreamPutData(m_DecodingStream, alaw_audio, alaw_audio.Length);
extracting the 16 kHz 16 bit pcm with Bass.BASS_ChannelGetData(m_Stream, pcm_audio, pcm_audio.Length);

It does not give me the 16 kHz 16 bit pcm, I expect. From what I can hear, it sound like it did not converted it at all.
I have attached the file that I am working on, if you need to have a look at it





Ian @ un4seen

  • Administrator
  • Posts: 23619
Re: convert alaw to linear pcm
« Reply #5 on: 8 Jun '21 - 16:08 »
Stream's created with BASS_StreamCreate only deal with PCM data. You can use BASS_StreamCreateFileUser instead for encoded data from custom sources. Note it needs to see a header to detect the format and initialize the decoder, so you will need to have that ready before making the call. If you have whole blocks of alaw data then you may be able to simply use BASS_StreamCreateFile instead (with mem=true) for each block, ie. pass it a block of alaw data (with header) in memory. If you like, you could then feed the decoded data to the push stream (m_DecodingStream) to get it into the mixer.

jakob

  • Posts: 137
Re: convert alaw to linear pcm
« Reply #6 on: 9 Jun '21 - 13:56 »
hi
Thank's. Do you think it is fast enough to do it that way, creating a new stream with BASS_StreamCreateFile every time i get a chunk of data?
My audio is real time streaming.
Now I am trying to use BASS_StreamCreateFileUser. But that gives me an error:

System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'

my code looks like this:
Code: [Select]
public void InitEncodedBassStream(MemoryStream ms)
        {
            int header_length = (int)ms.Length;
            IntPtr wav_header_pointer = Marshal.AllocHGlobal(header_length);
            byte[] wav_header = new byte[header_length];
            ms.Read(wav_header, 0, header_length);
            Marshal.Copy(wav_header, 0, wav_header_pointer, header_length);

            m_DecodingStream = Bass.BASS_StreamCreateFileUser(BASSStreamSystem.STREAMFILE_BUFFERPUSH, BASSFlag.BASS_STREAM_DECODE, new BASS_FILEPROCS(null, null, new FILEREADPROC(ReadCallback), null), wav_header_pointer);
           
        }
        private int ReadCallback(IntPtr buffer, int length, IntPtr user)
        {
            byte[] data = new byte[length];
            Marshal.Copy(user, data, 0, length);
            Marshal.Copy(data, 0, buffer, length);
            return length;
        }

The memorystream is actually an wav audio file. and the error is thrown when i call BASS_StreamCreateFileUser. The callback is not getting called.
I was hoping to just parse the wave header as the user parameter in order to let bass know what codec it is and the actual alaw data i would then parse with BASS_StreamPutFileData.

Ian @ un4seen

  • Administrator
  • Posts: 23619
Re: convert alaw to linear pcm
« Reply #7 on: 9 Jun '21 - 15:55 »
You will need to also provide FILECLOSEPROC and FILELENPROC callback functions in the BASS_StreamCreateFileUser call. I think you would also need to keep a reference to the delegates to prevent them being garbage collected by .Net. Please see the "Callbacks and Delegates" section in the "Interoperating with Unmanaged Code" page of the BASS.Net documentation for details on that stuff.

But I think BASS_StreamCreateFile might actually perform better for you, as it looks like there would be less .Net marshaling involved. The BASS_StreamCreateFile call itself should be very fast in this case.

herf

  • Posts: 3
Re: convert alaw to linear pcm
« Reply #8 on: 10 Jun '21 - 16:28 »
If you have whole blocks of alaw data then you may be able to simply use BASS_StreamCreateFile instead (with mem=true) for each block, ie. pass it a block of alaw data (with header) in memory.
How to achieve it? Do you have demo?