This set of questions came from a RackAFX user and book reader. I decided to post them here (and added one of my own at the end) to start a thread on debugging in Visual Studio. Debugging a real-time signal processing plug-in can be challenging, especially when you think your problem is in the processing function.
Before starting with the questions below, please make sure you understand how the Visual Studio debugger is setup. Many people do not understand that RackAFX configures your VS compiler to use it as the DLL's client. If you are not using RackAFX and are making VST or AU plug-ins, then you have to do this manually. Take a moment to open the project properties in your Plug-In in Visual Studio and click on the Debugging link. You will see that Command has the path to your RackAFX executable and Attach is set to YES. This was setup for you when you created your project (and it is re-inspected for accuracy and re-written if needed, every time you re-open a project in RackAFX). If you are using my Synth book and doing VST3 plug-ins, you need to set this up on your own (instructions are in the book).
When you start the debugger in Visual Studio (or remotely with the Debug button in RackAFX), the debugger attaches to the RackAFX executable (you will get an error if RackAFX is not running). At that point, any breakpoints you have set will change color from grey to red and they will be activated.
RackAFX has no idea you are debugging. It is just operating as normal. In effect, Visual Studio is "using" RackAFX and not the other way around.
Please leave thread related questions here. Note that in some cases, I have left multiple answers (A1, A2, etc..) so refer to them if you need to.
Q: Is there any good way to stop RackAFX when it’s processing a file and there’s an error in the ProcessAudioFrame routine? For instance, what I’m doing now there’s the need to solve a system of nonlinear equations and at times (for reasons I’m still unclear on) it seems to go into an infinite loop. I’d like to be able to do the equivalent of cntrl-C in Matlab and force RackAFX to quit processing in a case like this, but I don’t see any way to do so. Is there a way to do this?
A1: Hit the Stop button in RackAFX. If you really are in an infinite loop (and not just long processing) then this will do nothing. On occasion, I have been surprised to find that I did not have an infinite loop but some other time intensive thing going on (in one case, dealing with not-a-number issues) and after a moment, processing did eventually stop.
A2: If you are in an infinite loop and the Stop button does not work, then you can just unload the DLL from RackAFX the way you normally do with the Unload button on the right (with Debug, Make AU, etc...) or with the toolbar button (above the 6th slider column). The audio will continue to stream but your plug-in will be unloaded and not processing. You can not keep the debugger running and stop processing unless you simply use the Stop button in RackAFX.
A3: Usually, if you think you have an infinite loop in processAudioFrame() then you want to find out where it is and stop the debugger, wherever the code is trapped (I think this is the gist of your question). If you are trying to stop processing on-the-fly while the debugger is running, there are several ways to halt the debugger (and not halt RackAFX, which as you will see is not an active part of the VS debugger).
(1) Dropping breakpoints on the fly:
If you are sure your infinite loop is in the processAudioFrame() function, then start the debugger but don't set any breakpoints. Load the plug-in and start processing. When you think you are in the infinite loop, drop a breakpoint right inside of processAudioFrame() the same way you add one normally (by clicking in the column next to the line of code); place it in the processing code where you think you have a loop. The debugger will grind to a halt and you can then step through code, examine variables, etc... If the debugger does not halt, try other code in processAudioFrame() until you find it.
(2) Using Break All
You can also use the debugger's Break All function (Ctrl-Alt-Break) that looks like a pause button next to the stop button. The buttons only appear when you are actively debugging. (Build Menu on toolbar) Do the same thing as (1) and start the debugger with no breakpoints, load your plugin and go. Then, whenever you wish, use Break All to halt the debugger wherever it may be. This is a totally hit-and-miss approach and more often than not, it halts somewhere in RackAFX and you get a message saying it can't load symbols. Or, a find-file window pops up asking you to find some low level C file... However, if you are in a critical kind of loop (this happened to me once in Ableton where the plugin was underflowing and freezing the computer) then Break All may land you right in the middle of the problem.
(3) Conditional Breakpoint
You can set a breakpoint and make it conditional by right-clicking on the breakpoint and choose "Condition..." Then, you enter a standard C/C++ logical statement like
counter >= 65536;
where "counter" is a variable in your code. If you choose the option "Is true" then the debugger will halt when counter is >= the limit value.
You can also enter
counter = 0
and then use the "Has Changed" option to halt when counter changes from 0.
The use of conditional breakpoints, especially in the processing code, can cause the debugger to run very slowly and may cause audio to choke; if the condition doesn't take too many iterations, then this method works OK.
(4) Conditional Trap
My first boss Steve Busch at National Semiconductor showed me this. It is extremely simple and elementary. You just set your own conditional statement in the code and put a breakpoint on a meaningless line of code. The benefit of doing this is that you can create complex logical conditions for halting and it does not slow the debugger down like the conditional breakpoints do. So you could write:
if(counter >= 65536)
int trap = 0;
And then place the breakpoint on the "int trap = 0" line of code, and wait for it to get hit.
Q: When I’m using the debugger and stepping through code using breakpoints in VS 2013, it seems like I’m unable to switch back to the RackAFX window (in order to change the value of the controls, etc.). Is this normal? It seems like once we’re running rackafx in debug mode that we cannot go back to the rackafx ui.
A: First off, there is no such thing as "running rackafx in debug mode." When you hit the Debug button on the RackAFX UI, it simply starts the Visual Studio debugger remotely (the same way Rebuild works). Debugging mode is part of the compiler (XCode too, if you are doing AU) and has nothing to do with RackAFX. However, RackAFX is the plug-in's client and so it takes part in the whole thing as a client only. It does not provide debugging information or services.
This is correct and normal operation and will happen in any client & plug-in debugging scheme (such as Logic & AU/XCode or Cubase & VST3/VStudio). You can't go back while the debugger is halted. You need to hit the Continue button (looks like a play button) -- then, the audio processing thread will go back to normal and you can then go back to RackAFX and adjust controls. RackAFX should automatically pop into the foreground when this happens.
That is, unless you suddenly hit a breakpoint immediately after hitting the Continue button, which happens if you're breaking in processAudioFrame(). You need to either remove or disable your breakpoints. If you want to temporarily disable the breakpoints, do that in the Breakpoints window (Debug->Windows->Breakpoints or Alt-F9). In that window, you can check and uncheck the various breakpoints to enable/disable them. There is also a button that will let you enable/disable all of them at once. With the breakpoints disabled, once you hit the Continue button, RackAFX will go back to being active. You can also delete your breakpoints from within this window.
Q: Also, if we’re running rackafx from within the debugger and wish to just stop all processing, should hitting the “stop debugging” button in VS2013 also not stop RackAFX completely? I’m not experiencing this…instead, if I hit that button control goes back to RackAFX and it will just go ahead an run through the rest of the processing (essentially ignoring the breakpoints).
A: No, when you hit the Stop button, the debugger detaches from the RackAFX executable and stops its operation. RackAFX resumes operating as normal - and remember, RackAFX does not ignore breakpoints since it is not in any kind of debug mode. Visual Studio is ignoring the breakpoints.
Q: I’d like to be able to step through the code using breakpoints and, noticing an error for example, be able to immediately break the processing and go to the editor to make changes. Is there a way to do this?
A1: Yes, if in the special case that you just want to alter the value of a variable, pointer, etc... then you can use the Watch window and drag the variable name into it, then double click on the value to change it. Hit return, and the value is changed. This makes it easy to re-start loops or re-do something or find values that break your processing code.
A2: Yes, if you want to make changes to the code, then you can use the Edit and Continue function in Visual Studio. If you are using VS2012 or 2013 with RackAFX v6.2.6 or earlier, then you may notice that when you compile you get a warning that says:
ignoring /EDITANDCONTINUE due to 'SAFESEH' specification
To fix this and enable edit and continue, go to
Configuration Properties -> Linker -> Image has Safe Exception Handlers
and turn it OFF.
This (newer) configuration option is now automatically turned off for you when you create a new project in RackAFX versions greater than 6.2.6 so that you can use edit and continue without this chore.
To use this feature, halt on a break point but leave the debugger running (ie don't hit the stop button). Modify the code all you want - try to keep your modifications simple as you can always build upon them. After making the modification, hit the continue button. Your plug-in will then be recompiled. If there are no errors, the debugger will then magically start running again, using your new, modified code. In this way, you can make incremental changes easily. If you need to make really complex changes, it's usually best to stop, unload the plug-in and make the changes. Edit can continue will absolutely not restart the debugger (and release RackAFX) until you have working code.
Q: (added by Will) I hit a breakpoint in my code and I know that RackAFX is going to crash if I hit the Continue button (because of toxic code in my plugin). Can I force RackAFX to terminate from Visual Studio before this happens?
A: Yes, while you are stopped at the breakpoint, choose Debug->Terminate All. This will kill RackAFX, unload the plug-in and kill the debugger too but Visual Studio and your loaded project will remain.
Thanks so much for that detailed reply, which clarifies a lot! A couple of follow-ups:
- It seems the problem is not actually an infinite loop (in numerically computing the solution of the nonlinear system of equations I mentioned using the iterative Newton-Raphson method) but instead it just takes a long time for the solution to converge. As such I seem to have two choices: a) Set the max number of iterations to be lower than it should be for a close approximation to the solution to be found but on the other hand be able to hear smooth audio output, or b) Set the max iteration number higher so that the solution is better, but have the resulting audio output stutter a lot or have the plugin appear to be caught in a loop (which is what I thought was happening). This isn't really a "debugging" issue per se, so I'll post my question about this under the DSP algorithms section in the Forum.
- One way I was able to find that what I wrote above seems to be the case is by running the plugin with a high max iteration value chosen, but with the output written to a wav file. This takes a long time, but the resulting audio file sounds great when I play it with MediaPlayer.
QN: In writing the output to a wav file the RackAFX GUI seems to get greyed out with a little rotating circle as the cursor symbol (indicating that it's processing) and any an all attempts to do any of the things you mentioned in answers A1-A3 don't work since hitting any of the buttons in RackAFX are ignored since it's not possible to interact with the GUI anymore while things are processing. In fact, the RackAFX window says "RackAFX (not responding)". Do you know of any way to deal with this?
I'm running this with V6.2.6 with VS2013 on a late-2013 Macbook Pro (Mavericks) running Windows 7 via Parallels.
One other question...thanks in advance!
I'd like to compute a certain quantity (for debugging and analysis) over the course of all the processing that takes place in the processAudioFrame() function for a certain input file and then inspect its value at the end. What would be the best way to do this? Would it be to run it with the debugger and set a breakpoint someplace where execution would go only at the end (and if so, where would the best place for that be?), or is there someway to have the plugin code write a value to the RackAFX GUI and display it at the end?
OK, first question: you can still debug when processing into a WAV file - you have to start the debugger and set break points before starting the Process into WAV File operation. The RAFX GUI becomes inactive during the process because it is initiated from the main GUI window rather than using a parallel worker thread. The "not responding" message is a standard Windows message that you see when the process is taking a long time to complete (I get it with Visual Studio all the time). The fundamental difference in Process into WAV file is that it is not part of the audio callback thread as in the real-time case. Instead, it just brute-force processes the data through your plug-in all at once; there are no breaks when thread operation is handed over. In other words, when processing real-tine, the audio thread and GUI thread are constantly going in and out of activity, so you can get a break to manipulate the GUI - you can not do this when offline processing into the WAV file. As far as I know, this is the same for other DAWs too. So, debugging/GUI manipulation is limited with offline processing, but you should still be able to set and hit breakpoints. You can mimic GUI manipulation in the debugger by simply changing the underlying variable's value with the Watch window.
Question 2: you can use the built-in Status Window to send messages from your Plug-In back to RAFX - I use it all the time. You can also use the TRACE macro in Visual Studio to do the same thing. You can get information here:
You need a professional version of VS to use the built-in TRACE macro, but the link above shows how to add the functionality to VS Express too.
Another popular technique is data logging where you write information to a file, then examine the file afterwards to see what happened during the processing. File I/O with basic Windows (aka Win32) is pretty straightforward and well documented.
Most Users Ever Online: 152
Currently Browsing this Page:
Guest Posters: 1
Newest Members:Jas, Rowan, sojourn, fabhenr, rg1, Niklas, Wutru, Tim Campbell, Danny Jonel, Valentin
Moderators: W Pirkle: 573
Administrators: Tom: 74, JD Young: 80, Will Pirkle: 0, W Pirkle: 573, VariableCook: 3