Why is there latency in this C++ ALSA (Linux audio) program? - c++

I am exploring sound generation using C++ in Ubuntu Linux. Here is my code:
#include <iostream>
#include <cmath>
#include <stdint.h>
#include <ncurses.h>
//to compile: make [file_name] && ./[file_name]|aplay
int main()
{
initscr();
cbreak();
noecho();
nodelay(stdscr, TRUE);
scrollok(stdscr, TRUE);
timeout(0);
for ( int t=0;; t++ )
{
int ch = getch();
if (ch == 'q')
{
break;
}
uint8_t temp = t;
std::cout<<temp;
}
}
When this code is run, I want it to generate sound until I press "q" on my keyboard, after which I want the program to quit. This works fine; however, there is a noticeable delay between pressing the keyboard and the program quitting. This is not due to a delay with ncurses, as when I run the program without std::cout<<temp; (i.e. no sound generated), there is no latency
Is there a way to amend this? If not, how are real-time responsive audio programs written?
Edits and suggestions to the question are welcome. I am a novice to ALSA, so I am not sure if any additional details are required to replicate the bug.

The latency in the above loop is most likely due to delays introduced by the ncurses getch function.
Typically for realtime audio you will want to have a realtime audio thread running and a non-realtime user control thread running. The user control thread can alter the memory space of the real time audio thread which forces the real time audio loop to adjust synthesis as required.
In this gtkIOStream example, a full duplex audio class is created. The process method in the class can have your synthesis computation compiled in. This will handle the playback of your sound using ALSA.
To get user input, one possibility is to add a threaded method to the class by inheriting the FullDuplexTest class, like so :
class UIALSA : public FullDuplexTest, public ThreadedMethod {
void *threadMain(void){
while (1){
// use getchar here to block and wait for user input
// change the memory in FullDuplexTest to indicate a change in variables
}
return NULL;
}
public:
UIALSA(const char*devName, int latency) : FullDuplexTest(devName, latency), ThreadedMethod() {};
};
Then change all references to FullDuplexTest to UIALSA in the original test file (you will probably have to fix some compile time errors) :
UIALSA fullDuplex(deviceName, latency);
Also you will need to call UIALSA::run() to make sure the UI thread is running and listening for user input. You can add the call before you call "go" :
fullDuplex.run(); // start the UI thread
res=fullDuplex.go(); // start the full duplex read/write/process going.

Related

Rising edge interrupt triggering multiple times on STM32 Nucleo

I am using the STM32 NUCLEO-F401RE microcontroller board.
I have a speaker programmed to change frequency by a set amount when the joystick is pushed up/down. My issue is that sometimes (more often than not) when the joystick is pushed up/down the frequency increases/decreases multiple times, implying that the ISR is executing multiple times. Also, the InterruptIn object is set to trigger on the rising edge however sometimes it also executes on the falling edge (when the joystick is returend to neutral after pushing up/down). Any help for getting over this?
void upISR()
{
if (greenLED.getStatus())
{
myTicker.detach();
frequency+=200;
myTicker.attach(callback(&spkr, &Speaker::toggle), 0.5/frequency);
}
}
'
int main()
{
InterruptIn up(A2);
InterruptIn down(A3);
InterruptIn fire(D4);
up.rise(&upISR);
down.rise(&downISR);
fire.rise(&toggleISR);
redLED.on();
while (1){}
}
Mechanical switch bounce is a feature of all mechanical switches to a lesser or greater extent. It is often necessary to implement "debouncing" in software especially if the switch is directly driving an interrupt as in this case.
A quick Google search for software denounce techniques yields some rather poor techniques IMO. I seen it done poorly more times than well unfortunately.
I suggest that in the switch ISR you start (or restart in the event of a "bounce") a hardware timer for a period of say 20ms or so (longer than the switch bounce time, but shorter than the time you could possibly to genuinely release the switch). Then in the timer ISR, you test the state of the switch and change the frequency accordingly:
Pseudocode:
void upISR()
{
debounceTimerRestart() ;
}
void downISR()
{
debounceTimerRestart() ;
}
void debounceTimerISR()
{
debounceTimerStop() ;
tDirection dir = getJoystickDir() ;
swithc( dir )
{
case UP :
{
increaseFrquency() ;
}
break ;
case DN :
{
decreaseFrquency() ;
}
break ;
}
}
What this does is trigger a timer interrupt shortly ("debounce time") after the switch stops bouncing. Note the timer is "single-shot" not periodic.
Below I present an enhancement at #BenVoigt's suggestion (in comments). I am keeping it separate to make it clear it was his work. The above will generally work, but if you have a particularly poor switch the following would resolve issues, and at little cost, so you may as well:
void debounceTimerISR()
{
debounceTimerStop() ;
static tDirection previous_dir = CENTRE ;
tDirection dir = getJoystickDir() ;
// If the state changed...
if( previous_dir != dir )
{
previous_dir = dir ;
switch( dir )
{
case UP :
{
increaseFrquency() ;
}
break ;
case DN :
{
decreaseFrquency() ;
}
break ;
}
}
}
Simple do not use EXTI for mechanical yousticks and buttons.
Use regular interrupt (for example systick) to poll the status of the pins.
We clearly believe this is the normal and expected bouncing of the switch. Mechanically a switch is some piece of metal that when acted on moves that metal from one pole to another, even if they do not resemble a wiper and two poles. The metal that moves will collide and bounce, the electrical connection will show that. The bouncing is often slow enough for a processor to get multiple interrupts, although that may be an under-sampling of all the bounces possibly seen electrically. If you try to look at it on a scope the scope itself may not-intentionally be filtering some of it (but so will your chip).
One way to see the problem is as with anything, research first then write the application later. This is not a solution but a way to characterize the problem for your system
switch_isr ( void )
{
...
some_global_variable <<= 1;
some_global_variable |= (pin_state_register>>pin_number)&1;
...
}
main ( void )
{
...
some_local_variable = 0;
while(1)
{
if(some_local_variable != some_global_variable)
{
some_local_variable = some_global_variable;
primitive_hex_print(some_local_variable);
}
}
}
No reason to expect to see every state change in the shifted variable, but you should see some and get a feel for the problem. Another way is to just have a counter increment on every interrupt, print periodically in the foreground and you will see one button press may result in multiple counts. And from the time it takes for the printouts to stop changing roughly in human time the settling time.
Filtering is all about state changes per unit time though and you have to have some flavor of time, be it a loop in the foreground that polls some information set by the interrupt (up/down counters, etc), or state changes relative to a timer/clock.
I do not know what the complete rules are for your assignment, if you can only have an interrupt for each switch and not a timer, or preferably a timer instead, I do not see a clean solution that will actually work. You would have to filter in the foreground but all that is doing is polling a copy of the pin state collected by the interrupt and is that any different than not using the interrupt? You cannot use Clifford's answer if you cannot set a timer interrupt, if you could use a timer and an interrupt then you could just periodically sample the switch states with that interrupt or a copy of the pin state collected by the pin state change interrupts and filter in the timer interrupt. Not the same as Clifford's but in all cases you need state change history relative to time to see when the thing settles.
Without a time reference and states not changing with respect to time (which a pin interrupt cannot show since the state has not changed) you cannot filter out the bounces. Instead work on your dexterity and how you flick the joystick up and down.

SDL - How to play audio asynchronously in C++ without stopping code execution?

I am developing a clone of Asteroid in pure C++ and for that purpose, I need to add sounds to different events such as when a bullet is fired and when an explosion occurs. The issue however is that I don't have any experience with audio libraries.
I am using Simple DirectMedia Layer (SDL) and wrote a function named playsound() to play a sound in case a certain event occurs. The problem however is the fact that if an event occurs, playsound() is called and the code execution stops until the sound is wholly played out or until I return from the function (I delay the return using delay func).
What I would want to do is that the sound plays in the background without creating any lag for the rest of the Game. I am developing on Ubuntu 16.04 and can't use Windows PlaySound() either to call in the ASYNC flag.
Here is the function:
void playsound(string path) {
// Initialize SDL.
if (SDL_Init(SDL_INIT_AUDIO) < 0)
return;
// local variables
Uint32 wav_length; // length of our sample
Uint8 *wav_buffer; // buffer containing our audio file
SDL_AudioSpec wav_spec;
if(SDL_LoadWAV(path.c_str(), &wav_spec, &wav_buffer, &wav_length) == NULL){
return;
}
SDL_AudioDeviceID deviceId = SDL_OpenAudioDevice(NULL, 0, &wav_spec, NULL, 0);
SDL_QueueAudio(deviceId, wav_buffer, wav_length);
SDL_PauseAudioDevice(deviceId, 0);
SDL_Delay(50);
SDL_CloseAudioDevice(deviceId);
SDL_FreeWAV(wav_buffer);
SDL_Quit();
}
Your delay is stopping your code from executing, 50ms of delay is almost 2 frames at 33ms per frame or 3 frames at 16ms per frame, having a frame drop here and there might not be a problem, but you could see how calling several sounds in succession will slow your program down.
This is how I play sounds in my engine, using SDL2_mixer, (short sounds, for music you have another method called Mix_PlayMusic), it might be helpful to you. I have no lag (and I don't use any sleep or delays in my code). Once you call play() the sound should be played in full, unless there is something else pausing your code.
#pragma once
#include <string>
#include <memory>
#include <SDL2/SDL_mixer.h>
class sample {
public:
sample(const std::string &path, int volume);
void play();
void play(int times);
void set_volume(int volume);
private:
std::unique_ptr<Mix_Chunk, void (*)(Mix_Chunk *)> chunk;
};
And the cpp file
#include <sample.h>
sample::sample(const std::string &path, int volume)
: chunk(Mix_LoadWAV(path.c_str()), Mix_FreeChunk) {
if (!chunk.get()) {
// LOG("Couldn't load audio sample: ", path);
}
Mix_VolumeChunk(chunk.get(), volume);
}
// -1 here means we let SDL_mixer pick the first channel that is free
// If no channel is free it'll return an err code.
void sample::play() {
Mix_PlayChannel(-1, chunk.get(), 0);
}
void sample::play(int times) {
Mix_PlayChannel(-1, chunk.get(), times - 1);
}
void sample::set_volume(int volume) {
Mix_VolumeChunk(chunk.get(), volume);
}
Notice that I don't need to thread my model, every time something triggers a sound play the program keeps execution. (I guess SDL_Mixer plays in the main SDL thread).
For this to work, where you init SDL you'll also have to init the mixer as
if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024) < 0) {
// Error message if can't initialize
}
// Amount of channels (Max amount of sounds playing at the same time)
Mix_AllocateChannels(32);
And an example of how to play a sound would be
// at some point loaded a sample s with sample(path to wave mp3 or whatever)
s.play();
A few remarks, you don't need to use, but can, the code as it is, it is more of a simple example of using SDL2_mixer.
This mean functionality is lacking, you might want a tighter handling of sound, for example to stop a sound mid play (for some reason), you can do this if you play your sounds in different channels with the Mix_HaltChannel function, and the play() function could receive the channel where you want it to be played.
All these functions return error values, for example if no unreserved channel is available Mix_PlayChannel will return an error code.
Another thing you want to keep in mind is if you play the same sound several times it'll start to get blurry/you would not notice if the same sound is being played again. So you could add an integer to sample to count how many times a sample can be played.
If you REALLY want to thread your mixer/audio from the main SDL thread (and still only use SDL), you can just spawn a new SDL context in a thread and send in some way signals to play audio.
You want to load all necessary assets when initializing the game. Then, when you want to play them, they're loaded into the game memory and there will be no lags. And also play the sounds in a separate thread maybe, so it won't block your main thread.
There are several tools in C++ for asynchronous operations. You can try the most simple std::async:
auto handle = std::async(std::launch::async,
playsound, std::string{"/path/to/cute/sound"});
// Some other stuff. Your game logic doesn't blocked here.
handle.get(); // This can actually block.
You should specify flag std::launch::async, which means, that new thread will be used. Then name of callable needed to be executed and its parameters. Don't forget to include <future> header.

QCustomPlot Huge Amount of Data Plotting

I am trying to plot some serial data on my Qt Gui program using qcustomplot class. I had no trouble when I tried to plot low sampling frequency datas like 100 data/second. The graph was really cool and was plotting the data smoothly. But at high sampling rates such 1000data/second, plotter makes a bottleneck for serial read function. It slow downs serial there was a huge delay like 4-5 seconds apart from device. Straightforwardly, plotter could not reach the data stream speed. So, is there any common issue which i dont know about or any recommendation?
I thougth these scenarious,
1- to devide whole program to 2 or 3 thread. For example, serial part runs in one thread and plotting part runs in another thread and two thread communicates with a QSemaphore
2- fps of qcustom plot is limited. but there should be a solution because NI LABVIEW plots up to 2k of datas without any delay
3- to desing a new virtual serial device in usb protocol. Now, I am using ft232rl serial to usb convertor.
4- to change programming language. What is the situation and class support in C# or java for realtime plotting? (I know it is like a kid saying, but this is a pretex to be experienced in other languages)
My serial device send data funct(it is foo device for experiment there is no serious coding) is briefly that:
void progTask()
{
DelayMsec(1); //my delay function, milisecond
//read value from adc13
Adc13Read(adcValue.ui32Part);
sendData[0] = (char)'a';
sendData[1] = (char)'k';
sendData[2] = adcValue.bytes[0];
sendData[3] = (adcValue.bytes[1] & 15);
Qt Program read function is that:
//send test data
UARTSend(UART6_BASE,&sendData[0],4);
}
union{
unsigned char bytes[2];
unsigned int intPart;
unsigned char *ptr;
}serData;
void MedicalSoftware::serialReadData()
{
if(serial->bytesAvailable()<4)
{
//if the frame size is less than 4 bytes return and
//wait to full serial receive buffer
//note: serial->setReadBufferSize(4)!!!!
return;
}
QByteArray serialInData = serial->readAll();
//my algorithm
if(serialInData[0] == 'a' && serialInData[1] == 'k')
{
serData.bytes[0] = serialInData[2];
serData.bytes[1] = serialInData[3];
}else if(serialInData[2] == 'a' && serialInData[3] == 'k')
{
serData.bytes[0] = serialInData[0];
serData.bytes[1] = serialInData[1];
}
else if(serialInData[1] == 'a' && serialInData[2] == 'k')
{
serial->read(1);
return;
}else if(serialInData[0] == 'k' && serialInData[3] == 'a')
{
serData.bytes[0] = serialInData[1];
serData.bytes[1] = serialInData[2];
}
plotMainGraph(serData.intPart);
serData.intPart = 0;
}
And qcustom plot setting fuction is:
void MedicalSoftware::setGraphsProperties()
{
//MAIN PLOTTER
ui->mainPlotter->addGraph();
ui->mainPlotter->xAxis->setRange(0,2000);
ui->mainPlotter->yAxis->setRange(-0.1,3.5);
ui->mainPlotter->xAxis->setLabel("Time(s)");
ui->mainPlotter->yAxis->setLabel("Magnitude(mV)");
QSharedPointer<QCPAxisTickerTime> timeTicker(new QCPAxisTickerTime());
timeTicker->setTimeFormat("%h:%m:%s");
ui->mainPlotter->xAxis->setTicker(timeTicker);
ui->mainPlotter->axisRect()->setupFullAxesBox();
QPen pen;
pen.setColor(QColor("blue"));
ui->mainPlotter->graph(0)->setPen(pen);
dataTimer = new QTimer;
}
And the last is plot function:
void MedicalSoftware::plotMainGraph(const quint16 serData)
{
static QTime time(QTime::currentTime());
double key = time.elapsed()/1000.0;
static double lastPointKey = 0;
if(key-lastPointKey>0.005)
{
double value0 = serData*(3.3/4096);
ui->mainPlotter->graph(0)->addData(key,value0);
lastPointKey = key;
}
ui->mainPlotter->xAxis->setRange(key+0.25, 2, Qt::AlignRight);
counter++;
ui->mainPlotter->replot();
counter = 0;
}
Quick answer:
Have you tried:
ui->mainPlotter->replot(QCustomPlot::rpQueuedReplot);
according to the documentation it can improves performances when doing a lot of replots.
Longer answer:
My feeling on your code is that you are trying to replot as often as you can to get a "real time" plot. But if you are on a PC with a desktop OS there is no such thing as real time.
What you should care about is:
Ensure that the code that read/write to the serial port is not delayed too much. "Too much" is to be interpreted with respect to the connected hardware. If it gets really time critical (which seems to be your case) you have to optimize your read/write functions and eventually put them alone in a thread. This can go as far as reserving a full hardware CPU core for this thread.
Ensure that the graph plot is refreshed fast enough for the human eyes. You do not need to do a full repaint each time you receive a single data point.
In your case you receive 1000 data/s which make 1 data every ms. That is quite fast because that is beyond the default timer resolution of most desktop OS. That means you are likely to have more than a single point of data when calling your "serialReadData()" and that you could optimize it by calling it less often (e.g call it every 10ms and read 10 data points each time). Then you could call "replot()" every 30ms which would add 30 new data points each time, skip about 29 replot() calls every 30ms compared to your code and give you ~30fps.
1- to devide whole program to 2 or 3 thread. For example, serial part
runs in one thread and plotting part runs in another thread and two
thread communicates with a QSemaphore
Dividing the GUI from the serial part in 2 threads is good because you will prevent a bottleneck in GUI to block the serial communication. Also you could skip using semaphore and simply rely on Qt signal/slot connections (connected in Qt::QueuedConnection mode).
4- to change programming language. What is the situation and class
support in C# or java for realtime plotting? (I know it is like a kid
saying, but this is a pretex to be experienced in other languages)
Changing the programming language, in best case, won't change anything or could hurt your performances, especially if you go toward languages which are not compiled to native CPU instructions.
Changing the plotting library on the other hand could change the performances. You can look at Qt Charts and Qwt. I do not know how they compare to QCustomPlot though.

C++ How to wait for keyboard input for a limited time

I want my console application to stop and wait for the user to press a key. If there is no keyboard input after a limited time, let us say 2 seconds, execution should resume.
I know that no solution will be portable across all implementations, but are there at least simple solutions?
Some posts like this one or this one deal with similar issues, but they don’t seem to offer an answer to that specific problem.
If I could use ncurses (which I can't), I would do something like this using the getch() and timeout() functions:
#include <ncurses.h>
int main()
{
initscr(); // Start curses mode
cbreak(); // Turn off line buffering
timeout(2000); // Wait 2000 ms for user input
while (true) {
addstr("You have 2 sec. to press 'q', otherwise ...\n");
refresh();
int inKey = getch();
if (inKey == 'q') break;
}
endwin();
return 0;
}
One way of doing this would be to use low-level read() (assuming you are on Posix) coupled together with timeout signal. Since read() will exit with EINTR after signal processing, you'd know you reached the timeout.

How to put a time limit on user input?

I have tried various setups with input and my one second timer but nothing is working. The entire code is brought to a halt when it reaches the part asking for input. I have an unbuffered stream, so I don't need to press enter to send the input. Also the purpose of this is for a pac-man game I'm designing for terminal use. What I want is basically to have a one second interval where the user can enter a command. If no command is entered, I want the pac-man to continue moving the direction it was moving the last time a command was entered.
EDIT:
time_t startTime, curTime;
time(&startTime);
do
{
input=getchar();
time(&curTime);
} while((curTime - startTime) < 1);
You could try using alarm() (or similar timer function) to throw and have your application catch a SIGALRM, though this is definitely overkill for PacMac. Consider using a separate thread (POSIX thread) to control a timer.
On Unix, you can simply use select or poll with a timeout on the standard input file descriptor (STDIN_FILENO, or fileno(stdin)). I would not bring in mouse traps built of signals and threads just for this.
My gut feeling tells me this:
Have one thread dedicated to processing user input and putting key events into a queue
The timer-activated thread, on every activation, consumes all key events in the queue, using the one that happened last, at the point of thread activation.
Make sure your access to the queue is synchronized.
// I/O Thread:
while (!stop) {
input = getchar();
lock_queue();
queue.push_back(input);
unlock_queue();
}
// Timer Thread:
while (!stop) {
lock_queue();
if (queue.size() == 0) {
action = DEFAULT_ACTION;
} else {
// either handle multiple key events somehow
// or use the last key event:
action = queue.back();
queue.clear();
}
unlock_queue();
perform_action(action);
sleep();
}
Full example posted as a Github Gist.
You could use a non-blocking input function such as getch() but it isn't very cross platform compatible.
Ideally you should be using events to update the game state, depending on which OS you are targeting you could use the OS events for key press or maybe a library such as SDL.