Search code examples
c#audiowavopentkopenal

Save to audio file with OpenAL


I am using OpenTK, more precisely OpenAL. I am able to capture the sound from the mic, but then I want to save the data to a WAVE file.

I found a example how to write a wave file and the result is almost working.

I believe my file header is correct, but I have some doubt of the correct way to write the buffer data to the file.

I first tried recording with this settings:

  • 44100 Hz
  • 16 bits
  • 2 channels

Playing the file was just some noise

I changed to a mono setting (1 channel). This time I was able to reproduce the audio, but it was played 2 times faster

Is it possible that I should first transform the data from ALC.CaptureSamples before writing them directly to the stream ?

To add some code, first I have the capture samples, that I think work correctly (I got from the TestUnit from OpenAL repo):

int totalSamples = 0;
while (totalSamples < buffer.Length && !_cancellationToken.IsCancellationRequested)
{
  int samplesAvailable = ALC.GetInteger(_captureDevice, AlcGetInteger.CaptureSamples);
  if (samplesAvailable < 512) continue;
  int samplesToRead = Math.Min(samplesAvailable, buffer.Length - totalSamples);
  ALC.CaptureSamples(_captureDevice, ref buffer[totalSamples], samplesToRead);
  totalSamples += samplesToRead;
  spinWait.SpinOnce();
}

And then I write to the stream simply:

// headers writing...
// ...
sw.Write(buffer, 0, totalSamples);

I don't find any sample about OpenAL and file writing...
Is everything correct ?
Am I missing some steps ?


Solution

  • OK @fdcpp gave me an hint with not full samples being written. So to make it working, for a mono 16bit sound, the buffer should be ushort and not byte type.

    There are some missing knowledge about sound audio specs from my side 😔

    So the specific parts of code are:

    // Capture the device
    _captureDevice = ALC.CaptureOpenDevice(null, 44100, ALFormat.Mono16, 1024);
    ...
    // Start recording
    var buffer = new ushort[44100 * 16];
    ...
    // Writing data
    ushort bytePerBloc = 1 * (16 / 8);
    using (MemoryStream memoryStream = new())
    using (BinaryWriter sw = new(memoryStream))
    {
      sw.Write(['R', 'I', 'F', 'F']);
      sw.Write(totalSamples * bytePerBloc + 36);
      ...
      sw.Write(['d', 'a', 't', 'a']);
      sw.Write(totalSamples * bytePerBloc); // size of buffer
    
      for (int i = 0; i < totalSamples; i++)
      {
        sw.Write(buffer[i]);
      }
    ...
    }
    

    And now it's working.

    Next step to try the same with stereo 16bits 😅