Combining libsndfile and RtAudio?

671 Views Asked by At

So, i've been experimenting around with RtAudio and libsndfile.

The task seemed to be simple:

1.) Read some samples into a buffer with libsndfile (using the SndfileHandle class and readf())

2.) Use RtAudio to play back the samples

BUT, for some reason, all i get is noize, and massive distortion ... i've tried to read the samples as 16 Bit PCM (using a short buffer), and use the RTAUDIO_SINT16 format to play it back. No success ... as a matter of fact, i've tried many different combinations, and there's only noise ...

The closest i've gotten to actual playback was using int16_t for the buffer and RTAUDIO_SINT16. Seems logical, right? Anyway, it's still like using a bitcrusher. Tried JACK and ALSA, and many different combinations of buffer sized, to no avail ...

Any hint on how to combine those two ?

Could it be a problem that i'm using a static buffer (just for experimentation, wouldn't do that in a final product, of course ...)?

1

There are 1 best solutions below

0
On

Ok, answering my own question here, it was only a confusion between some parameters, mainly frames and samples ... while a sample is just a single sample, a frame are the samples of all channels ...

#include <iostream>
#include <sndfile.hh>
#include "RtAudio.h"

/*
* Audio-Wiedergabe mit RtAudio und libsndfile !
*/

// Call
int fplay( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
         double streamTime, RtAudioStreamStatus status, void *userData )
{


  int16_t *buffer = (int16_t *) outputBuffer;

  // ok, i know this is not the best way to do file i/o in the audio thread, but 
  // this is just for demonstration purposes ... 
  SndfileHandle *sndfile = reinterpret_cast<SndfileHandle*>(userData);

  // Error handling !
  if ( status ){
    std::cout << "Stream underflow detected!" << std::endl;
  }


  // 'readf()' liest frames
  // 'read()' liest einzelne Samples !
  // ACHTUNG! Frames != Samples
  // ein Frame = Samples für alle Kanäle
  // d.h. |Samples| = Kanäle * Frames !
  sndfile->readf(buffer, nBufferFrames);

  return 0;
}

int main () {
  // Damit das Programm funktioniert, muss eine 16Bit PCM Wave-Datei im
  // gleichen Ordner liegen !
    const char * fname = "test.wav" ;

  // Soundfile-Handle aus der libsndfile-Bibliothek
    SndfileHandle file = SndfileHandle (fname) ;

  // Alle möglichen Infos über die Audio-Datei ausgeben !
  std::cout << "Reading file: " << fname << std::endl;
  std::cout << "File format: " << file.format() << std::endl;
  std::cout << "PCM 16 BIT: " << (SF_FORMAT_WAV | SF_FORMAT_PCM_16) << std::endl;
  std::cout << "Samples in file: " << file.frames() << std::endl;
  std::cout << "Samplerate " << file.samplerate() << std::endl;
  std::cout << "Channels: " << file.channels() << std::endl;

  // Die RtAudio-Klasse ist gleichermassen dac und adc, wird hier aber nur als dac verwendet !
    RtAudio dac;
  if ( dac.getDeviceCount() < 1 ) {
    std::cout << "\nNo audio devices found!\n";
    return 0;
  }

  // Output params ...
  RtAudio::StreamParameters parameters;
  parameters.deviceId = dac.getDefaultOutputDevice();
  parameters.nChannels = 2;
  parameters.firstChannel = 0;
  unsigned int sampleRate = 44100;

  // ACHTUNG! Frames != Samples
  // ein Frame = Samples für alle Kanäle
  // d.h. |Samples| = Kanäle*Frames !
  unsigned int bufferFrames = 1024;


  try {
    dac.openStream( &parameters, NULL, RTAUDIO_SINT16,
                    sampleRate, &bufferFrames, &fplay, (void *)&file);
    dac.startStream();
  }
  catch ( RtAudioError& e ) {
    e.printMessage();
    return 0;
  }

  char input;
  std::cout << "\nPlaying ... press <enter> to quit.\n";
  std::cin.get( input );
  try {
    // Stop the stream
    dac.stopStream();
  }
  catch (RtAudioError& e) {
    e.printMessage();
  }
  if ( dac.isStreamOpen() ) dac.closeStream();

  return 0 ;

}