I'm working on a project in c, where I'm going to make some heavy physics calculations, and I want the ability to see the results when I'm finished. The way it works now is that I run GLUT on the main thread, and use a seperate thread (pthread) to do input (from terminal) and calculations. I currently use glutTimerFunc to do the animation, but the problem is that that function will fire every given time intervall no matter what. I can stop the animation by using an if statement in the animation function, stopping the variables from being updatet, but this uses a lot of unnecessary resources (I think).
To fix this problem I was thinking that I could use an extra thread with a custom timer function that I could controll myself (without glutMainLoop messing things up). Currently this is my test function to check if this would work (meaning that the function itself is in no way finished). It runs in a seperate thread createt just before glutMainLoop:
void *threadAnimation() {
while (1) {
if (animationRun) {
rotate = rotate+0.00001;
if (rotate>360) {
rotate = rotate-360;
}
glutSetWindow(window);
glutPostRedisplay();
}
}
}
The specific problem I have is that the animation just runs for a couple of seconds, and then stops. Does anybody know how I can fix this? I am planning to use timers and so on later, but what I'm looking for is a way to ensure that glutPostRedisplay will be sent the right place. I tought glutSetWindow(window) was the solution, but apparently not. If I remove glutSetWindow(window) the animation still works, just not for as long, but runs much faster (so maybe glutSetWindow(window) takes a lot of resources?)
btw the variable "window" is created like this:
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(854, 540);
glutInitWindowPosition(100, 100);
window = glutCreateWindow("Animation View");
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
timerInt = pthread_create(&timerThread, NULL, &threadAnimation, NULL);
glutMainLoop();
I don't acctually know if this is correct, but it compiles just fine. Any help is greatly appriciated!
Here's a little idea, create class that will contain all dynamic settings:
class DynamicInfo {
public int vertexCount;
public float *vertexes;
...
DynamicInfo &operator=( const DynamicInfo &origin);
};
And than main application will contain those:
DynamicInfo buffers[2];
int activeBuffer = 0;
In animation thread just draw (maybe use some threads locks for one variable):
DynamicInfo *current = buffers + activeBuffer; // Or rather use reference
In calculations:
// Store currently used buffer as current (for future manipulation)
DynamicInfo *current = buffers + activeBuffer;
// We finished calculations on activeBuffer[1] so we may propagate it to application
activeBuffer = (activeBuffer + 1)%2;
// Let actual data propagate to current buffer
(*current) = buffers[activeBuffer];
Again it's locking one variable.
Related
I'm learning c and messing around with xcb lib (instead of X11) on a raspberry pi4.
The problem is that when implementing the events loop with xcb_poll_for_event instead of xcb_wait_for_event, one core of four is 100% full. What am I doing wrong? And is there any benefit of using wait_for_event (blocking way) instead of xcb_poll_for_event(non blocking)?
The goal is to create a window where the user interact with keyboard/mouse/gamepad on objects, like a game. Can anyone give a hand?
The relevant code is:
int window_loop_test(xcb_connection_t *connection, Display *display){
/* window loop non blocked waiting for events */
int running = 1;
while (running) {
xcb_generic_event_t *event = xcb_poll_for_event(connection);
if (event) {
switch (event->response_type & ~0x80) {
case XCB_EXPOSE: {
// TODO
break;
}
case XCB_KEY_PRESS: {
/* Quit on 'q' key press */
/* write key pressed on console */
const xcb_key_press_event_t *press =
(xcb_key_press_event_t *)event;
XKeyEvent keyev;
keyev.display = display;
keyev.keycode = press->detail;
keyev.state = press->state;
char key[32];
XLookupString(&keyev, key, sizeof(key) - 1, NULL, NULL);
// key[len] = 0;
printf("Key pressed: %s\n", key);
printf("Mod state: %d\n", keyev.state);
if (*key == 'q')
running = 0;
break;
}
}
free(event);
}
}
return 0;
}
Polling and waiting each have their advantages and are good for different situations. Neither is "wrong" per se, but you need to use the correct one for your specific use case.
xcb_wait_for_event(connection) is a blocking call. The call will not return until an event is available, and the return value is is that event (unless an error occurs). It is good for situations where you only want the thread to respond to events, but otherwise not do anything. In that case, there is no need to spend CPU resources when no events are coming in.
xcb_poll_for_event(connection) is a non-blocking call. The call always returns immediately, but the result will be NULL if no event is available. It is good for situations where you want the thread to be able to do useful work even if no events are coming in. As you found out, it's not good if the thread only needs to respond to events, as it can consume CPU resources unnecessarily.
You mention that your goal is to create a game or something similar. Given that there are many ways to architect a game, either function can be suitable. But there are a couple of basic things to keep in mind that will determine which function you want to use. There may be other considerations as well, but this will give you an idea of what to look out for.
First of all, is your input system running on the same thread as other systems (simulation, rendering, etc)? If so, it's probably important to keep that thread available for work other than waiting for input events. In this case, xcb_poll_for_event() is almost required, otherwise your thread will be blocked until an event comes in. However, if your input system is on its own thread that doesn't block your other threads, it may be acceptable to use xcb_wait_for_event() and let that thread sleep when no events are coming in.
The second consideration is how quickly you need to respond to input events. There's often a delay in waking up a thread, so if fast response times are important you'll want to avoid letting the thread sleep in the first place. Again, xcb_poll_for_event() will be your friend in this case. If response times are not critical, xcb_wait_for_events() is an option.
I want to create a realtime sine generator using apples core audio framework. I want do do it low level so I can learn and understand the fundamentals.
I know that using PortAudio or Jack would probably be easier and I will use them at some point but I would like to get this to work first so I can be confident to understand the fundamentals.
I literally searched for days now on this topic but no one seems to have ever created a real time wave generator using core audio trying to optain low latency while using C and not Swift or Objective-C.
For this I use a project I set up a while ago. It was first designed to be a game. So after the Application starts up, it will enter a run loop. I thought this would perfectly fit as I can use the main loop to copy samples into the audio buffer and process rendering and input handling as well.
So far I get sound. Sometimes it works for a while then starts to glitch, sometimes it glitches right away.
This is my code. I tried to simplify if and only present the important parts.
I got multiple questions. They are located in the bottom section of this post.
Applications main run loop. This is where it all starts after the window is created and buffers and memory is initialized:
while (OSXIsGameRunning())
{
OSXProcessPendingMessages(&GameData);
[GlobalGLContext makeCurrentContext];
CGRect WindowFrame = [window frame];
CGRect ContentViewFrame = [[window contentView] frame];
CGPoint MouseLocationInScreen = [NSEvent mouseLocation];
BOOL MouseInWindowFlag = NSPointInRect(MouseLocationInScreen, WindowFrame);
CGPoint MouseLocationInView = {};
if (MouseInWindowFlag)
{
NSRect RectInWindow = [window convertRectFromScreen:NSMakeRect(MouseLocationInScreen.x, MouseLocationInScreen.y, 1, 1)];
NSPoint PointInWindow = RectInWindow.origin;
MouseLocationInView= [[window contentView] convertPoint:PointInWindow fromView:nil];
}
u32 MouseButtonMask = [NSEvent pressedMouseButtons];
OSXProcessFrameAndRunGameLogic(&GameData, ContentViewFrame,
MouseInWindowFlag, MouseLocationInView,
MouseButtonMask);
#if ENGINE_USE_VSYNC
[GlobalGLContext flushBuffer];
#else
glFlush();
#endif
}
Through using VSYNC I can throttle the loop down to 60 FPS. The timing is not super tight but it is quite steady. I also have some code to throttle it manually using mach timing which is even more imprecise. I left it out for readability.
Not using VSYNC or using mach timing to get 60 iterations a second also makes the audio glitch.
Timing log:
CyclesElapsed: 8154360866, TimeElapsed: 0.016624, FPS: 60.155666
CyclesElapsed: 8174382119, TimeElapsed: 0.020021, FPS: 49.946926
CyclesElapsed: 8189041370, TimeElapsed: 0.014659, FPS: 68.216309
CyclesElapsed: 8204363633, TimeElapsed: 0.015322, FPS: 65.264511
CyclesElapsed: 8221230959, TimeElapsed: 0.016867, FPS: 59.286217
CyclesElapsed: 8237971921, TimeElapsed: 0.016741, FPS: 59.733719
CyclesElapsed: 8254861722, TimeElapsed: 0.016890, FPS: 59.207333
CyclesElapsed: 8271667520, TimeElapsed: 0.016806, FPS: 59.503273
CyclesElapsed: 8292434135, TimeElapsed: 0.020767, FPS: 48.154209
What is important here is the function OSXProcessFrameAndRunGameLogic. It is called 60 times a second and it is passed a struct containing basic information like a buffer for rendering, keyboard state and a sound buffer which looks like this:
typedef struct osx_sound_output
{
game_sound_output_buffer SoundBuffer;
u32 SoundBufferSize;
s16* CoreAudioBuffer;
s16* ReadCursor;
s16* WriteCursor;
AudioStreamBasicDescription AudioDescriptor;
AudioUnit AudioUnit;
} osx_sound_output;
Where game_sound_output_buffer is:
typedef struct game_sound_output_buffer
{
real32 tSine;
int SamplesPerSecond;
int SampleCount;
int16 *Samples;
} game_sound_output_buffer;
These get set up before the application enters its run loop.
The size for the SoundBuffer itself is SamplesPerSecond * sizeof(uint16) * 2 where SamplesPerSecond = 48000.
So inside OSXProcessFrameAndRunGameLogic is the sound generation:
void OSXProcessFrameAndRunGameLogic(osx_game_data *GameData, CGRect WindowFrame,
b32 MouseInWindowFlag, CGPoint MouseLocation,
int MouseButtonMask)
{
GameData->SoundOutput.SoundBuffer.SampleCount = GameData->SoundOutput.SoundBuffer.SamplesPerSecond / GameData->TargetFramesPerSecond;
// Oszi 1
OutputTestSineWave(GameData, &GameData->SoundOutput.SoundBuffer, GameData->SynthesizerState.ToneHz);
int16* CurrentSample = GameData->SoundOutput.SoundBuffer.Samples;
for (int i = 0; i < GameData->SoundOutput.SoundBuffer.SampleCount; ++i)
{
*GameData->SoundOutput.WriteCursor++ = *CurrentSample++;
*GameData->SoundOutput.WriteCursor++ = *CurrentSample++;
if ((char*)GameData->SoundOutput.WriteCursor >= ((char*)GameData->SoundOutput.CoreAudioBuffer + GameData->SoundOutput.SoundBufferSize))
{
//printf("Write cursor wrapped!\n");
GameData->SoundOutput.WriteCursor = GameData->SoundOutput.CoreAudioBuffer;
}
}
}
Where OutputTestSineWave is the part where the buffer is actually filled with data:
void OutputTestSineWave(osx_game_data *GameData, game_sound_output_buffer *SoundBuffer, int ToneHz)
{
int16 ToneVolume = 3000;
int WavePeriod = SoundBuffer->SamplesPerSecond/ToneHz;
int16 *SampleOut = SoundBuffer->Samples;
for(int SampleIndex = 0;
SampleIndex < SoundBuffer->SampleCount;
++SampleIndex)
{
real32 SineValue = sinf(SoundBuffer->tSine);
int16 SampleValue = (int16)(SineValue * ToneVolume);
*SampleOut++ = SampleValue;
*SampleOut++ = SampleValue;
SoundBuffer->tSine += Tau32*1.0f/(real32)WavePeriod;
if(SoundBuffer->tSine > Tau32)
{
SoundBuffer->tSine -= Tau32;
}
}
}
So when the Buffers are created at start up also Core audio is initialized which I do like this:
void OSXInitCoreAudio(osx_sound_output* SoundOutput)
{
AudioComponentDescription acd;
acd.componentType = kAudioUnitType_Output;
acd.componentSubType = kAudioUnitSubType_DefaultOutput;
acd.componentManufacturer = kAudioUnitManufacturer_Apple;
AudioComponent outputComponent = AudioComponentFindNext(NULL, &acd);
AudioComponentInstanceNew(outputComponent, &SoundOutput->AudioUnit);
AudioUnitInitialize(SoundOutput->AudioUnit);
// uint16
//AudioStreamBasicDescription asbd;
SoundOutput->AudioDescriptor.mSampleRate = SoundOutput->SoundBuffer.SamplesPerSecond;
SoundOutput->AudioDescriptor.mFormatID = kAudioFormatLinearPCM;
SoundOutput->AudioDescriptor.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsNonInterleaved | kAudioFormatFlagIsPacked;
SoundOutput->AudioDescriptor.mFramesPerPacket = 1;
SoundOutput->AudioDescriptor.mChannelsPerFrame = 2; // Stereo
SoundOutput->AudioDescriptor.mBitsPerChannel = sizeof(int16) * 8;
SoundOutput->AudioDescriptor.mBytesPerFrame = sizeof(int16); // don't multiply by channel count with non-interleaved!
SoundOutput->AudioDescriptor.mBytesPerPacket = SoundOutput->AudioDescriptor.mFramesPerPacket * SoundOutput->AudioDescriptor.mBytesPerFrame;
AudioUnitSetProperty(SoundOutput->AudioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&SoundOutput->AudioDescriptor,
sizeof(SoundOutput->AudioDescriptor));
AURenderCallbackStruct cb;
cb.inputProc = OSXAudioUnitCallback;
cb.inputProcRefCon = SoundOutput;
AudioUnitSetProperty(SoundOutput->AudioUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Global,
0,
&cb,
sizeof(cb));
AudioOutputUnitStart(SoundOutput->AudioUnit);
}
The initialization code for core audio sets the render callback to OSXAudioUnitCallback
OSStatus OSXAudioUnitCallback(void * inRefCon,
AudioUnitRenderActionFlags * ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData)
{
#pragma unused(ioActionFlags)
#pragma unused(inTimeStamp)
#pragma unused(inBusNumber)
//double currentPhase = *((double*)inRefCon);
osx_sound_output* SoundOutput = ((osx_sound_output*)inRefCon);
if (SoundOutput->ReadCursor == SoundOutput->WriteCursor)
{
SoundOutput->SoundBuffer.SampleCount = 0;
//printf("AudioCallback: No Samples Yet!\n");
}
//printf("AudioCallback: SampleCount = %d\n", SoundOutput->SoundBuffer.SampleCount);
int SampleCount = inNumberFrames;
if (SoundOutput->SoundBuffer.SampleCount < inNumberFrames)
{
SampleCount = SoundOutput->SoundBuffer.SampleCount;
}
int16* outputBufferL = (int16 *)ioData->mBuffers[0].mData;
int16* outputBufferR = (int16 *)ioData->mBuffers[1].mData;
for (UInt32 i = 0; i < SampleCount; ++i)
{
outputBufferL[i] = *SoundOutput->ReadCursor++;
outputBufferR[i] = *SoundOutput->ReadCursor++;
if ((char*)SoundOutput->ReadCursor >= (char*)((char*)SoundOutput->CoreAudioBuffer + SoundOutput->SoundBufferSize))
{
//printf("Callback: Read cursor wrapped!\n");
SoundOutput->ReadCursor = SoundOutput->CoreAudioBuffer;
}
}
for (UInt32 i = SampleCount; i < inNumberFrames; ++i)
{
outputBufferL[i] = 0.0;
outputBufferR[i] = 0.0;
}
return noErr;
}
This is mostly all there is to it. This is quite long but I did not see a way to present all needed information in a more compact way. I wanted to show all because I am by no means a professional programmer. If there is something you feel is missing, pleas tell me.
My feeling tells me that there is something wrong with the timing. I feel the function OSXProcessFrameAndRunGameLogic sometimes needs more time so that the core audio callback is already pulling samples out of the buffer before it is fully written by OutputTestSineWave.
There is actually more stuff going on in OSXProcessFrameAndRunGameLogic which I did not show here. I am "software rendering" very basic stuff into a framebuffer which is then displayed by OpenGL and I also do keypress checks in there because yeah, its the main function of functionality. In the future this is the place where I would like to handle the controls for multiple oscillators, filters and stuff.
Anyway even if I stop the Rendering and Input handling from being called every iteration I still get audio glitches.
I tried pulling all the sound processing in OSXProcessFrameAndRunGameLogic into an own function void* RunSound(void *GameData) and changed it to:
pthread_t soundThread;
pthread_create(&soundThread, NULL, RunSound, GameData);
pthread_join(soundThread, NULL);
However I got mixed results and was not even sure if multithreading is done like that. Creating and destroying threads 60 times a second didn't seem the way to go.
I also had the idea to let sound processing happen on a completely different thread before the application actually runs into the main loop. Something like two simultaneously running while loops where the first processes audio and the latter UI and input.
Questions:
I get glitchy audio. Rendering and input seem to work correctly but audio sometimes glitches, sometimes it doesn't. From the code I provided, can you maybe see me doing something wrong?
Am I using the core audio technology in a wrong way in order to achieve real time low latency signal generation?
Should I do sound processing in a separate thread like I talked about above? How would threading in this context be done correctly? It would make sense to have a thread only dedicated for sound am I right?
Am I right that the basic audio processing should not be done in the render callback of core audio? Is this function only for outputting the provided sound buffer?
And if sound processing should be done right here, how can I access information like the keyboard state from inside the callback?
Are there any resources you could point me to that I maybe missed?
This is the only place I know where I can get help with this project. I would really appreciate your help.
And if something is not clear to you please let me know.
Thank you :)
In general when dealing with low-latency audio you want to achieve the most deterministic behaviour possible.
This, for example, translates to:
Don't hold any locks on the audio thread (priority inversion)
No memory allocation on the audio thread (takes often too much time)
No file/network IO on the audio thread (takes often too much time)
Question 1:
There are indeed some problems with your code for when you want to achieve continuous, realtime, non-glitching audio.
1. Two different clock domains.
You are providing audio data from a (what I call) a different clock domain than the clock domain asking for data. Clock domain 1 in this case is defined by your TargetFramesPerSecond value, clock domain 2 defined by Core Audio. However, due too how scheduling works you have no guarantee that you thread is finishing in time and on time. You try to target your rendering to n frames per second, but what happens when you don't make it time wise? As far as I can see you don't compensate for the deviation a render cycle took compared to the ideal timing.
The way threading works is that ultimately the OS scheduler decides when your thread is active. There are never guarantees and this causes you render cycles to be not very precise (in term of precision you need for audio rendering).
2. There is no synchronisation between the render thread and the Core Audio rendercallback thread.
The thread where the OSXAudioUnitCallback runs is not the same as where your OSXProcessFrameAndRunGameLogic and thus OutputTestSineWave run. You are providing data from your main thread, and data is being read from the Core Audio render thread. Normally you would use some mutexes to protect you data, but in this case that's not possible because you would run into the problem of priority inversion.
A way of dealing with race conditions is to use a buffer which uses atomic variables to store the usage and pointers of the buffer and let only 1 producer and 1 consumer use this buffer.
Good examples of such buffers are:
https://github.com/michaeltyson/TPCircularBuffer
https://github.com/andrewrk/libsoundio/blob/master/src/ring_buffer.h
3. There are a lot of calls in you audio render thread which prevent deterministic behaviour.
As you wrote you are doing a lot more inside the same audio render thread. Changes are quite high that there will be stuff going on (under the hood) which prevents your thread from being on time. Generally, you should avoid calls which take either too much time or are not deterministic. With all the OpenGL/keypres/framebuffer rendering there is no way to be certain you thread will "arrive on time".
Below are some resources worth looking into.
Question 2:
AFAICT generally speaking, you are using the Core Audio technology correctly. The only problem I think you have is on the providing side.
Question 3:
Yes. Definitely! Although, there are multiple ways of doing this.
In your case you have a normal-priority thread running to do the rendering and a high-performance, realtime thread on which the audio render callback is being called. Looking at your code I would suggest putting the generation of the sine wave inside the render callback function (or call OutputTestSineWave from the render callback). This way you have the audio generation running inside a reliable high prio thread, there is no other rendering interfering with the timing precision and there is no need for a ringbuffer.
In other cases where you need to do "non-realtime" processing to get audiodata ready (think of reading from a file, reading from a network or even from another physical audio device) you cannot run this logic inside the Core Audio thread. A way to solve this is to start a separate, dedicated thread to do this processing. To pass the data to the realtime audio thread you would then make use of the earlier mentioned ringbuffer.
It basically boiles down to two simple goals: for the realtime thread it is necessary to have the audio data available at all times (all render calls), if this failes you will end up sending invalid (or better zeroed) audio data.
The main goal for the secondary thread is to fill up the ringbuffer as fast as possible and to keep the ringbuffer as full as possible. So, whenever there is room to put new audio data into the ringbuffer the thread should do just that.
The size of the ringbuffer in this case will dicate how much tolerance there will be for delay. The size of the ringbuffer will be a balance between certainty (bigger buffer) and latency (smaller buffer).
BTW. I'm quite certain Core Audio has all the facilities to do all this for you.
Question 4:
There are multiple ways of achieving you goal, and rendering the stuff inside the render callback from Core Audio is definitely one of them. The one thing you should keep in mind is that you have to make sure the function returns in time.
For changing parameters to manipulate the audio rendering you'll have to find a way of passing messages which enables the reader (audio renderer function) to get messages without locking and waiting. The way I have done this is to create a second ringbuffer which hold messages from which the audio renderer can consume. This can be as simple as a ringbuffer which hold structs with data (or even pointers to data). As long as you stick to the rules of no locking.
Question 5:
I don't know what resources you are aware of but here are some must-reads:
http://atastypixel.com/blog/four-common-mistakes-in-audio-development/
http://www.rossbencina.com/code/real-time-audio-programming-101-time-waits-for-nothing
https://developer.apple.com/library/archive/qa/qa1467/_index.html
You basic problem is that you are trying to push audio from your game loop instead of letting the audio system pull it; e.g. instead of always having (or quickly being able to create *) enough audio samples ready for the amount requested by the audio callback to be pulled by the audio callback. The "always" has to account for enough slop to cover timing jitter (being called late or early or too few times) in your game loop.
(* with no locks, semaphores, memory allocation or Objective C messages)
I am new to Gtk and this is my very first Gtk project. I am using C and Gtk+ 2 on Code::Blocks on Windows 7. In my project, I have a main window which initially shows a home screen, holding a button to "Run" the project and some other buttons ("Exit", "About" etc). When this "Run" button is clicked, the program has to read and write some large text files, and then show a new screen with some new data (I am creating this new screen by destroying all the previous children of the main window and putting in new stuff into it).
Now due to large sizes of those text files, the program lags for some time when Run is clicked, so I want to show an intermediate screen having some message like "Loading...". But I am unable to do it, because this intermediate screen is never shown.
Here is what I have; I hope the code makes it clear:
GtkWidget *windowMain = NULL;
GtkWidget *vboxMain = NULL;
//These 2 are global.
void home_screen() //Works well
{
//...Created new main window...
//...Created new main vbox...
//...Added vboxMain to windowMain...
GtkWidget *menuButton = gtk_button_new_with_label("Run");
g_signal_connect (menuButton, "clicked", G_CALLBACK (intermediate_screen), NULL);
gtk_box_pack_start (GTK_BOX (vboxMain), menuButton, TRUE, TRUE, 0); //Add button to vboxMain.
gtk_widget_show_all (windowMain);
}
void intermediate_screen() //Is not shown at correct time
{
// CLEAR MAIN WINDOW:
GList *children, *iter;
children = gtk_container_get_children(GTK_CONTAINER(windowMain));
for(iter = children; iter != NULL; iter = g_list_next(iter))
gtk_widget_destroy(iter->data);
g_list_free(children);
GtkWidget *label = gtk_label_new(NULL);
gtk_label_set_markup(GTK_LABEL(label1), "<b>Loading...</b>");
gtk_container_add (GTK_CONTAINER (windowMain), label);
gtk_widget_show_all(windowMain);
prepare_files(); //Function to work with the text files
}
void prepare_files() //Starts working before "Loading..." is shown
{
//Some file handling which takes some time to complete.
next_screen();
}
void next_screen()
{
// CLEAR MAIN WINDOW AGAIN TO CLEAR THE "Loading..." LABEL:
GList *children, *iter;
children = gtk_container_get_children(GTK_CONTAINER(windowMain));
for(iter = children; iter != NULL; iter = g_list_next(iter))
gtk_widget_destroy(iter->data);
g_list_free(children);
vboxMain = gtk_vbox_new (FALSE, 5);
gtk_widget_set_size_request (vboxMain, 600, 600);
gtk_container_add (GTK_CONTAINER (windowMain), vboxMain);
//Add components to the vboxMain
gtk_widget_show_all(windowMain);
}
Problem is that intermediate_screen() shows the "Loading" message only after the prepare_files() function has been completed - and hence it is of no use. During all that time, only homescreen is being shown... In fact, the next_screen() is shown immediately after, so "Loading" does not even show up. But shouldn't it show the loading message during all that lag, as the prepare_files() function is called later?
What am I doing wrong and how should I correctly do it?
Sorry if this was something obvious. As I said I am a beginner in Gtk+ .
Gtk+ drawing happens on a timer that fires in the same thread as your code. In other words the drawing code can only run when your code is not running: when "Run" is clicked, the next draw can only happen after intermediate_screen() has returned (and "Loading..." screen has already been replaced).
You could add some hacks in intermediate_screen() that runs a few iterations of the main loop so at least one draw would happen but that would still be bad and unresponsive design. There are 2 possible better solutions:
Use an asynchronous API like GIO to read and write to files: this means no function in your code ever runs long enough to disrupt drawing or interacting with the UI. Implementing this is a little more complex than synchronous reads (like the ones you probably use now), one possible short version is: Create a GFile, call g_file_read_async(), in the callback call g_file_read_finish(), create a GDataInputStream from the GFileInputStream you get, then use g_data_input_stream_read_*_async() functions to start reading lines or other chunks of the file, and in that callback get the data with g_data_input_stream_read_*_finish().
Alternatively create a new thread and read the data in that thread using the same reading code you now use. The down side is that you now have to deal with thread-safety yourself -- this can be difficult, and threading bugs are the hardest to debug.
In my opinion option #1 is the best compromise in almost all situations where an asynchronous API is available. Note that if your own processing of the file contents takes a long time, you should do that in small chunks as well (usually it works out nicely so you can e.g. read one line or larger chunk asynchronously and process the line/chunk in the callback).
I have a simple GUI application I wrote in C for the RaspBerry PI while using GTK+2.0 to handle the actual UI rendering. The application so far is pretty simple, with just a few pushbuttons for testing simple functions I wrote. One button causes a thread to be woken up which prints text to the console, and goes back to sleep, while another button stops this operation early by locking a mutex, changing a status variable, then unlocking the mutex again. Fairly simple stuff so far. The point of using this threaded approach is so that I don't ever "lock up" the UI during a long function call, forcing the user to be blocked on the I/O operations completing before the UI is usable again.
If I call the following function in my thread's processing loop, I encounter a number of issues.
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <stdio.h>
#include <errno.h>
using namespace std;
using namespace cv;
#define PROJECT_NAME "CAMERA_MODULE" // Include before liblog
#include <log.h>
int cameraAcquireImage(char* pathToImage) {
if (!pathToImage) {
logError("Invalid input");
return (-EINVAL);
}
int iErr = 0;
CvCapture *capture = NULL;
IplImage *frame, *img;
//0=default, -1=any camera, 1..99=your camera
capture = cvCaptureFromCAM(CV_CAP_ANY);
if(!capture) {
logError("No camera interface detected");
iErr = (-EIO);
}
if (!iErr) {
if ((frame = cvQueryFrame(capture)) == NULL) {
logError("ERROR: frame is null...");
iErr = (-EIO);
}
}
if (!iErr) {
CvSize size = cvSize(100, 100);
if ((img = cvCreateImage(size, IPL_DEPTH_16S, 1)) != NULL) {
img = frame;
cvSaveImage(pathToImage, img);
}
}
if (capture) {
cvReleaseCapture(&capture);
}
return 0;
}
The function uses some simple OpenCV code to take a snapshot with a webcam connected to my Raspberry PI. It issues warnings of VIDIOC_QUERYMENU: Invalid argument to the console, but still manages to acquire the images and save them to a file for me. However, my GUI becomes sluggish, and sometimes hangs. If it doesn't outright hang, then the window goes blank, and I have to randomly click all over the UI area until I click on where a pushbutton would normally be located, and the UI finally re-renders again rather than showing a white empty layout.
How do I go about resolving this? Is this some quirk in OpenCv when using it as part of a Gtk+2.0 application? I had originally had my project setup as a GTK3.0 application, but it wouldn't run due to some check in GTK preventing multiple versions from being included in a single application, and it seems OpenCv is an extension of GTK+2.0.
Thank you.
there is something quite broken here:
CvSize size = cvSize(100, 100);
if ((img = cvCreateImage(size, IPL_DEPTH_16S, 1)) != NULL) {
img = frame;
cvSaveImage(pathToImage, img);
}
first, you create a useless 16-bit image (why even?), then you reassign(alias) that pointer to your original image, and then you don't cvReleaseImage it (memleak).
please, stop using opencv's deprecated c-api. please.
any noob will shoot into his foot using this (one of the main reasons to get rid of it)
also, you can only use ~30% of opencv's functionality this way (the opencv1.0 set)
again, please, stop using opencv's deprecated c-api. please.
Didn't you forget to free the img pointer ?
Also, I did in the past an app that stored uncompressed images on the disk, and things used to become sluggish. In fact, what was taking time was storing the images on the disk, as it was exceeding the max bandwidth of what the filesystem layer could handle.
So try to see is you can store compressed images instead (trading some CPU to save bandwidth), or store your images in RAM in a queue and save them afterwards (in a separate thread, or in an idle handler). Of course, if the video you capture is too long, you may end up with an Out Of Memory condition. I only had sequences of a few seconds to store, so that did the trick.
I use g_thread_new() to create a new thread to implement a flash image effect but only to show the later image but not to flash the 2 images.
And this is the code in the GThreadFunc function:
gdk_threads_enter();
draw_effect(background_map[mbullet.x][mbullet.y +1]);
g_usleep(110000);
draw_background(background_map[mbullet.x][mbullet.y +1]);
gdk_threads_leave();
And this is draw_**()function:
void draw_effect(GtkWidget *widget)
{
gtk_image_set_from_pixbuf(widget,fire_effect);
};
But the program can only show the image that draw_background()draws not draw_effct() does.
Unless I remove the gdk_threads_enter() andgdk_threads_leave() code,can the image flash as I wish.
What's wrong with my code?Can anybody help me?
You're modifying a widget from a thread other than the main thread, which usually leads to all kinds of problems and unexpected behaviors in many GUI libraries, not only gtk.
I do understand the motivation to use a thread here though, since you need to wait a while before redrawing the background.
I recommend that you call draw_effect directly instead of creating a thread, and then use g_timeout_add to schedule a call to a function that will redraw the background.
It should be something like this (please modify as needed and do read the docs):
Define this function:
gboolean
redraw_background (gpointer user_data) {
// ... get references to background_map and mbullet here ...
draw_background(background_map[mbullet.x][mbullet.y +1]);
return FALSE; // so it isn't called again
}
And elsewhere:
// Draw what you need to draw
draw_effect(background_map[mbullet.x][mbullet.y +1]);
// Schedule draw_background 110 ms from now
// user_data will be passed as a parameter to redraw_background
g_timeout_add (110, // milliseconds
redraw_background,
user_data);