I'm writing a drum trigger detector in c++ with PortAudio and libsndfile. The part when the program detects the input and decides if the sound should be played is done but I have no idea how to implement the libsndfile version. The only thing I could do is to play the wav file with sndfile without reading the trigger input and without using callback function in a separate project but I'm not able to connect these two. The wav file should be played when trigLevel > 900.0f && legalHit is true. The program uses ASIO driver. If there is any other library for playing wav file and has ASIO support, I'm willing to switch.
#include <iostream>
#include <portaudio.h>
#include <vector>
const int SAMPLE_RATE = 44100;
const int FRAMES_PER_BUFFER = 256;
int audioCallback(const void* inputBuffer, void* outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void* userData);
int main() {
PaError err;
err = Pa_Initialize();
if (err != paNoError) {
std::cerr << "PortAudio error: " << Pa_GetErrorText(err) << std::endl;
return 1;
}
PaDeviceIndex defaultInputDevice = Pa_GetDefaultInputDevice();
if (defaultInputDevice == paNoDevice) {
std::cerr << "No default input device found!" << std::endl;
Pa_Terminate();
return 1;
}
// Set up input parameters
PaStreamParameters inputParameters;
inputParameters.device = defaultInputDevice;
inputParameters.channelCount = 1;
inputParameters.sampleFormat = paFloat32;
inputParameters.suggestedLatency = 0;
inputParameters.hostApiSpecificStreamInfo = nullptr;
int hostNr = Pa_GetHostApiCount();
std::vector<const PaHostApiInfo*> infoVertex;
for (int t = 0; t < hostNr; ++t) {
infoVertex.push_back(Pa_GetHostApiInfo(t));
}
PaHostApiIndex defaultHostApi = Pa_GetDefaultHostApi(); // Get the index of the default host API
std::cout << "Currently used audio driver:" << std::endl;
std::cout << " Name: " << infoVertex[defaultHostApi]->name << std::endl;
std::cout << " Type: " << infoVertex[defaultHostApi]->type << std::endl;
std::cout << " Device Count: " << infoVertex[defaultHostApi]->deviceCount << std::endl;
std::cout << "---------------------------------------- " << std::endl;
for (int t = 0; t < hostNr; ++t) {
const PaHostApiInfo* hostApiInfo = infoVertex[t];
std::cout << "Host API " << t << ":" << std::endl;
std::cout << " Name: " << hostApiInfo->name << std::endl;
std::cout << " Type: " << hostApiInfo->type << std::endl;
std::cout << " Device Count: " << hostApiInfo->deviceCount << std::endl;
// You can access more fields from PaHostApiInfo if needed
// For example: hostApiInfo->defaultInputDevice, hostApiInfo->defaultOutputDevice, etc.
std::cout << std::endl;
}
PaStream* stream;
err = Pa_OpenStream(&stream,
&inputParameters,
nullptr,
SAMPLE_RATE,
FRAMES_PER_BUFFER,
paClipOff,
audioCallback,
nullptr);
if (err != paNoError) {
std::cerr << "PortAudio error: " << Pa_GetErrorText(err) << std::endl;
Pa_Terminate();
return 1;
}
err = Pa_StartStream(stream);
if (err != paNoError) {
std::cerr << "PortAudio error: " << Pa_GetErrorText(err) << std::endl;
Pa_CloseStream(stream);
Pa_Terminate();
return 1;
}
std::cout << "Microphone level (normalized):" << std::endl;
while (true) {
Pa_Sleep(1000);
}
// Cleanup
err = Pa_StopStream(stream);
if (err != paNoError) {
std::cerr << "PortAudio error: " << Pa_GetErrorText(err) << std::endl;
}
err = Pa_CloseStream(stream);
if (err != paNoError) {
std::cerr << "PortAudio error: " << Pa_GetErrorText(err) << std::endl;
}
Pa_Terminate();
return 0;
}
// Audio callback function
int audioCallback(const void* inputBuffer, void* outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void* userData) {
const float* input = static_cast<const float*>(inputBuffer);
// RMS
float trigLevel = 0.0f;
for (unsigned long i = 0; i < framesPerBuffer; ++i) {
trigLevel += input[i] * input[i];
}
trigLevel = std::sqrt(trigLevel / framesPerBuffer) * float(std::pow(10.0, 5));
static bool legalHit = true;
if (trigLevel > 900.0f && legalHit) {
std::cout << "Trigger Input Level (RMS): " << trigLevel << std::endl;
// This is where the sound should be played
Sleep(50);
legalHit = false;
}
else if (trigLevel < 900.0f)
{
legalHit = true;
}
return paContinue;
}