How to use RTAudio to sound card IO
Date: 2023-12-15Last modified: 2024-11-02
Table of contents
Introduction
This post is related to a very basic use of the RTAudio library to produced waves on the sound card. My pourpose is to understand how to use a sound card for digital communication.
#include <chrono>
#include <iostream>
#include <rtaudio/RtAudio.h>
#include <thread>
Output - Generator
// Two-channel sawtooth wave generator.
// The callback function will automatically be invoked when the underlying audio system needs data for output.
int saw_generator_callback(
void *outputBuffer,
void *inputBuffer,
unsigned int nBufferFrames,
double streamTime,
RtAudioStreamStatus status,
void *userData )
{
unsigned int i, j;
double *buffer = (double *)outputBuffer;
double *lastValues = (double *)userData;
if( status ) {
std::cout << "Stream underflow detected!" << std::endl;
}
// Write interleaved audio data.
for( i = 0; i < nBufferFrames; i++ ) {
for( j = 0; j < 2; j++ ) {
*buffer++ = lastValues[j];
lastValues[j] += 0.005 * ( j + 1 + ( j * 0.1 ) );
if( lastValues[j] >= 1.0 )
lastValues[j] -= 2.0;
}
}
return 0;
}
Input - read from the microphone
A return value of 1 will cause the stream to finish draining its internal buffers and then halt (equivalent to calling the RtAudio::stopStream() function).
A return value of 2 will cause the stream to stop immediately (equivalent to calling the RtAudio::abortStream() function).
## Main function
```cpp
int main()
{
RtAudio *audio_dac_adc = NULL;
// Default RtAudio constructor
try {
audio_dac_adc = new RtAudio();
}
catch( RtAudioError &error ) {
error.printMessage();
exit( EXIT_FAILURE );
}
// Determine the number of devices available
unsigned int number_of_devices = audio_dac_adc->getDeviceCount();
if( number_of_devices == 0 ) {
delete audio_dac_adc;
return 0;
}
// Scan through devices for various capabilities
RtAudio::DeviceInfo info;
for( unsigned int device_index = 1; device_index <= number_of_devices; device_index++ ) {
try {
info = audio_dac_adc->getDeviceInfo( device_index );
}
catch( RtAudioError &error ) {
error.printMessage();
break;
}
std::cout << "device = " << device_index << " " << info.name << "\n";
std::cout << ": maximum output channels = " << info.outputChannels << "\n";
std::cout << ": maximum input channels = " << info.inputChannels << "\n";
std::cout << ": maximum duplex channels = " << info.duplexChannels << "\n";
if( info.nativeFormats | RTAUDIO_SINT8 ) {
std::cout << ": native support for 8-bits signed integer\n";
}
if( info.nativeFormats | RTAUDIO_SINT16 ) {
std::cout << ": native support for 16-bits signed integer\n";
}
if( info.nativeFormats | RTAUDIO_SINT24 ) {
std::cout << ": native support for 24-bits signed integer\n";
}
if( info.nativeFormats | RTAUDIO_SINT32 ) {
std::cout << ": native support for 32-bits signed integer\n";
}
if( info.nativeFormats | RTAUDIO_FLOAT32 ) {
std::cout << ": native support for 32-bits Normalized between plus/minus 1.0\n";
}
if( info.nativeFormats | RTAUDIO_FLOAT64 ) {
std::cout << ": native support for 64-bits Normalized between plus/minus 1.0\n";
}
bool found_192 = false;
for( const auto sample_rate : info.sampleRates ) {
std::cout << ": supported sample rate: " << sample_rate << "\n";
if( sample_rate == 192000 ) {
found_192 = true;
}
}
if( found_192 ) {
// file:///usr/share/doc/librtaudio-dev/api_ref/recording.html
RtAudio::StreamParameters *outputParameters = NULL;
RtAudio::StreamParameters inputParameters
= { .deviceId = device_index, .nChannels = info.inputChannels, .firstChannel = 0 };
RtAudioFormat format = RTAUDIO_SINT16; // 16-bit signed integer.
unsigned int sampleRate = 192000;
unsigned int bufferFrames = 256; // 256 sample frames
RtAudioCallback callback = &record_callback;
void *user_data = NULL;
// double user_data[2] = { 0, 0 };
RtAudio::StreamOptions *options = NULL;
RtAudioErrorCallback errorCallback = NULL;
try {
audio_dac_adc->openStream(
outputParameters,
&inputParameters,
format,
sampleRate,
&bufferFrames,
callback,
user_data,
options,
errorCallback );
audio_dac_adc->startStream();
}
catch( RtAudioError &e ) {
e.printMessage();
exit( 0 );
}
for( auto t = 0; t < 5; ++t ) {
std::cout << "\nWaiting for 1s - recording...\n";
std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
}
try {
// Stop the stream
audio_dac_adc->stopStream();
}
catch( RtAudioError &e ) {
e.printMessage();
}
if( audio_dac_adc->isStreamOpen() ) {
audio_dac_adc->closeStream();
}
break;
}
}
// Playback
{
RtAudio::StreamParameters output_parameters;
RtAudio::StreamParameters *input_parameters = NULL;
output_parameters.deviceId = audio_dac_adc->getDefaultOutputDevice();
output_parameters.nChannels = 2;
output_parameters.firstChannel = 0;
unsigned int sampleRate = 44100;
unsigned int bufferFrames = 256; // 256 sample frames
double data[2] = { 0, 0 };
try {
audio_dac_adc->openStream(
&output_parameters,
input_parameters,
RTAUDIO_FLOAT64,
sampleRate,
&bufferFrames,
&saw_generator_callback,
(void *)&data );
audio_dac_adc->startStream();
}
catch( RtAudioError &e ) {
e.printMessage();
exit( 0 );
}
for( auto t = 0; t < 3; ++t ) {
std::cout << "\nWaiting for 1s - playing...\n";
std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
}
try {
// Stop the stream
audio_dac_adc->stopStream();
}
catch( RtAudioError &e ) {
e.printMessage();
}
if( audio_dac_adc->isStreamOpen() ) {
audio_dac_adc->closeStream();
}
}
// Clean up
delete audio_dac_adc;
return 0;
}
Possible output
device = 1 Built-in Audio Analog Stereo (echo cancelled with Built-in Audio Analog Stereo)
: maximum output channels = 1
: maximum input channels = 1
: maximum duplex channels = 0
: native support for 8-bits signed integer
: native support for 16-bits signed integer
: native support for 24-bits signed integer
: native support for 32-bits signed integer
: native support for 32-bits Normalized between plus/minus 1.0
: native support for 64-bits Normalized between plus/minus 1.0
: supported sample rate: 8000
: supported sample rate: 16000
: supported sample rate: 22050
: supported sample rate: 32000
: supported sample rate: 44100
: supported sample rate: 48000
: supported sample rate: 96000
: supported sample rate: 192000
Waiting for 1s - recording...
CB: counter=0 dt=0s t=0s
CB: counter=100 dt=0.00133333s t=0.133333s
CB: counter=200 dt=0.00133333s t=0.266667s
CB: counter=300 dt=0.00133333s t=0.4s
CB: counter=400 dt=0.00133333s t=0.533333s
CB: counter=500 dt=0.00133333s t=0.666667s
CB: counter=600 dt=0.00133333s t=0.8s
CB: counter=700 dt=0.00133333s t=0.933333s
Waiting for 1s - recording...
CB: counter=800 dt=0.00133333s t=1.06667s
CB: counter=900 dt=0.00133333s t=1.2s
CB: counter=1000 dt=0.00133333s t=1.33333s
CB: counter=1100 dt=0.00133333s t=1.46667s
CB: counter=1200 dt=0.00133333s t=1.6s
CB: counter=1300 dt=0.00133333s t=1.73333s
CB: counter=1400 dt=0.00133333s t=1.86667s
Waiting for 1s - recording...
CB: counter=1500 dt=0.00133333s t=2s
CB: counter=1600 dt=0.00133333s t=2.13333s
CB: counter=1700 dt=0.00133333s t=2.26667s
CB: counter=1800 dt=0.00133333s t=2.4s
CB: counter=1900 dt=0.00133333s t=2.53333s
CB: counter=2000 dt=0.00133333s t=2.66667s
CB: counter=2100 dt=0.00133333s t=2.8s
CB: counter=2200 dt=0.00133333s t=2.93333s
Waiting for 1s - recording...
CB: counter=2300 dt=0.00133333s t=3.06667s
CB: counter=2400 dt=0.00133333s t=3.2s
CB: counter=2500 dt=0.00133333s t=3.33333s
CB: counter=2600 dt=0.00133333s t=3.46667s
CB: counter=2700 dt=0.00133333s t=3.6s
CB: counter=2800 dt=0.00133333s t=3.73333s
CB: counter=2900 dt=0.00133333s t=3.86667s
Waiting for 1s - recording...
CB: counter=3000 dt=0.00133333s t=4s
CB: counter=3100 dt=0.00133333s t=4.13333s
CB: counter=3200 dt=0.00133333s t=4.26667s
CB: counter=3300 dt=0.00133333s t=4.4s
CB: counter=3400 dt=0.00133333s t=4.53333s
CB: counter=3500 dt=0.00133333s t=4.66667s
CB: counter=3600 dt=0.00133333s t=4.8s
CB: counter=3700 dt=0.00133333s t=4.93333s
Waiting for 1s - playing...
Waiting for 1s - playing...
Waiting for 1s - playing...
References
- [RTAudio doxygen documentation (local)](file:///usr/share/doc/librtaudio-dev/api_ref/index.html)
apt install librtaudio-doc