I have a black-box that emits signals (say calls a function) at unknown and varying intervals. Each emitted signal marks half a period in a square wave. The goal would be to produce the sound of said square wave.
My original idea was to open a portaudio stream and every time the signal is emitted play a short square wave, then silence. My assumption was that if the signal is emitted 400 times a second then this would result in a 200hz square wave.
Instead on my windows machine I hear a pop then nothing, definitely not what I know a 200hz square wave to be, inside a virtualbox ubuntu installation sometimes I also receive underrun occured errors.
#include <stdio.h>
#include <stdlib.h>
#include <portaudio.h>
#include <time.h>
#include <math.h>
void e(PaError err)
{
if (err != paNoError)
{
Pa_Terminate();
fprintf(stderr, "An error occurred while using the portaudio stream\n");
fprintf(stderr, "Error number: %d\n", err);
fprintf(stderr, "Error message: %s\n", Pa_GetErrorText(err));
}
}
typedef struct
{
int play;
} paData;
PaStreamParameters outputParameters;
static PaStream *stream;
static paData data;
static int count;
static int paCallback(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo *timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData)
{
paData *data = (paData *)userData;
float *out = (float *)outputBuffer;
(void)inputBuffer;
for (int i = 0; i < framesPerBuffer; i++)
{
if (data->play)
{
*out++ = 1.0f;
}
}
data->play = 0;
return 0;
}
int main()
{
printf("Initializing buzzer\n");
e(Pa_Initialize());
outputParameters.device = Pa_GetDefaultOutputDevice();
if (outputParameters.device == paNoDevice)
{
fprintf(stderr, "Error: No default output device.\n");
return 1;
}
outputParameters.channelCount = 1;
outputParameters.sampleFormat = paFloat32;
outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency;
outputParameters.hostApiSpecificStreamInfo = NULL;
e(Pa_OpenStream(&stream, NULL, &outputParameters, 44100, 256, paClipOff, paCallback, &data));
e(Pa_StartStream(stream));
struct timespec interval;
interval.tv_sec = 0;
interval.tv_nsec = 2500000;
struct timespec pause;
pause.tv_sec = 2;
pause.tv_nsec = 0;
// emulate the black-box to play a 400hz signal
for (int i = 0; i < 1000; i++)
{
data.play = 1;
nanosleep(&interval, NULL);
}
nanosleep(&pause, NULL);
e(Pa_StopStream(stream));
e(Pa_CloseStream(stream));
Pa_Terminate();
}