Cabbage Logo
Back to Cabbage Site

Strangeness in the output console when the performance ends

  • Clone the Cabbage repo:
    https://github.com/rorywalsh/cabbage
  • install Visual Studio 2017 community with the full C++ development tools. It’s a fair size of a package, expect to part with about 3/4gigs of hard disk space.
  • Download JUCE version 5.2.3, and then build the Projucer project with VS2017
  • Download and extract the VST SDK to a folder on your C drives called SDKs.
  • Do the same with the ASIO stuff
  • You should have Csound installed, if it’s in the default location great, otherwise might be best to install it there.

With all that done, open the newly build Projucer app and then open the CabbageIDE.jucer file in the Cabbage root dir. Hit save, this will create the VS studio project for your machine. You can then launch Cabbage.sln to get going. Note this will jut build the standalone version, but I don’t think you need anything else in order to test the problem here.

Following your instructions, I’m also able to get a crash. Will investigate now.

I think that all the troubles come from the “subinstr” statement. If you insert the “instr 2” code directly in the “instr 1”, without the subinstr, it doesn’t crash anymore.

P.S.: what version I should clone? Master or develop?

Master. Btw, you may need to set the appropriate target for your version of Windows. If you hit a problem there, go to Solution->Retarget and note the available Windows SDK build versions. Then in the Projucer enter the correct SDK version as shown in the pic below.

For what it’s worth, I’ve had issues with subinstr in the past. I’m not sure memory is correctly released when using it. I remember running some Csound code through the OSX memory profiler at one point and noticing some strange issues.

The debugger takes me straight to the Csound object destructor when this crash happens. I’m not sure why CsoundQT doesn’t suffer the same fate, but it certainly looks like an issue with Csound. I think you’re better off using UDOs instead of sub instruments?

I suspected it, but it’s very strange that in CsoundQT there are no crashes. Maybe CsoundQT uses a different approach or “statements order” in starting/stopping a Csound program?

CsoundQT uses the Csound audio and MIDI IO interfaces by default. Cabbage disables these and uses its own callbacks which I guess increases the chances of issues like this. However, I need to do it this way to accommodate running Csound as a plugin.

By the way, I use subinstr to make my code play different instruments for different groups of notes on the midi keyboard and to make easy changes to the groups. For example, I have something like:

instr 1040, 1041, 1042, 1043, 1044, 1045
		...
		...
		out		aOut
endin

instr 1
	iFreq	=		p4
	iAmp	=		p5
	iNumKey	=		notnum() - 20
    
	if (iNumKey < 1 || iNumKey > 88) goto skipnote
	
	instr	=		1000 + iNumKey
	aOut	subinstr	instr, iFreq, iAmp
	
	aOut	=		aOut * madsr(0.01, 0, 1, 5)
		outs		aOut, aOut
			    
	skipnote:
endin

As you can see, Instr 1 “subinstr” to the right instrument, based on the key number of the note (for the sake of simplicity I omitted the code for groups other than 40-45).
In this simple schema, if I want to make the keys 46 and 47 play from the instr 1040, all I have to do is to add “, 1046, 1047” to the right of the “instr 1040…” statement. Similarly, if I want to isolate the keys 42 and 43 and make them play from a separated instrument, all I have to do is to remove 1042 and 1043 from the “instr 1040…” statement and create a new instrument for the extracted key numbers:

instr 1042, 1043
		...
		...
		out		aOut
endin

I don’t know if I can do this with UDOs in such an easy and elegant way, and I suspect that subinstr could be much more efficient (for example, being that actually in Csound the passage of parameters to the UDOs is done “by value”, each time you call an UDO with a-rate input/output params it’s like to copy an array of “ksmps” double floats for each a-type parameter… From my experiments, this could slow down very much the performance, and it’s for this reason that as long as Csound will not allow passing parameters by reference I will always be reluctant to use UDOs to process a-rate signals in real-time).

I see your point. If you fancy building Csound for Windows you can step through the debugger and see what’s up?

Yes, for now I’m trying to build Juce and Cabbage (I don’t have a fast internet connection so the downloads take some time…).

Esp. VS2017, it’s a juggernaut.

Exactly, what you mean to build the Projucer project? It’s a file I have to open in Visual Studio? Keep in mind that I have 0 experience with Juce, so I do not even know what Projucer is… :sob:

Yeah, open ProJucer.sln and build it.

When it runs, open the CabbageIDE.jucer file from within the Projucer and hit ‘save project’. That should give you the sln project you need for Cabbage. If you have Csound installed in the default directory and you have the ASIO and VST stuff in C:/SDKs then it should build out of the box.

Building of Cabbage successful! :slight_smile:
I had to change the Windows SDK version in CabbageIDE.jucer too.

That’s great. Next up Csound :wink:

Building of Csound successful too (after much struggling I have to say)!!

Now I have absolutely no idea how to debug Cabbage so that Visual Studio could point to me to the right Csound source C file when there is a crash…

Did you build Csound in debug mode? You should probably rename your Csound dir so the system doesn’t find the installed Csound. And you should add the path to your newly build Csound. Then reload the Cabbage project in the ProJucer and modify the paths to the Csound libs. Hit save, and rebuild Cabbage. That should do the trick.

Ok, now I can get to the error in the debugger. The code crashes in the Csound file auxfd.c, exactly in this function (I added a CRASH HERE!! string to the right of the statement where it crashes):

/* release all xds in instr auxp chain */
/*   called by insert at orcompact     */

void auxchfree(CSOUND *csound, INSDS *ip)
{
    if (UNLIKELY(csound->oparms->odebug))
      auxchprint(csound, ip);
    while (LIKELY(ip->auxchp != NULL)) {        /* for all auxp's in chain: */
      void  *auxp = (void*) ip->auxchp->auxp;   "**CRASH HERE!!**"
      AUXCH *nxt = ip->auxchp->nxtchp;
      memset((void*) ip->auxchp, 0, sizeof(AUXCH)); /*  delete the pntr     */
      csound->Free(csound, auxp);                   /*  & free the space    */
      ip->auxchp = nxt;
    }
    if (UNLIKELY(csound->oparms->odebug))
      auxchprint(csound, ip);
}

I can elaborate until a certain point, then I’m unable to understand, because there are too many things of Csound, Cabbage and Juce inner working that I don’t know.

The error is an “access violation” at reading at the address pointed by “ip->auxchp”.

From what I understand, the crash occurs because in that particular situation generated by the 2nd run of my Csound program, there is a pointer (ip->auxchp) that points to a memory region that is no longer accessible and so that statement generates an access violation exception. Now, the question is: why this pointer is NOT NULL? If that pointer was released by Csound code, the pointer should be NULL and we would not have any error.
For this reason, and being that in CsoundQT there is no such error, I suspect that there is some memory area that is released by Cabbage or Juce code before Csound itself…

But what this “ip->auxchp” is? An auxiliary channel for something? Midi channel?

Your guess is as good as mine. I really have very little experience in the inner workings of Csound. You could probably post to the Csound-dev list, or file an issue on github page? The biggest obstacle here is none of the devs have a Cabbage build, so I’m not sure how much assistance they can be. But they can certainly help you understand the Csound code that’s causing the problem.

I found another thing that could be useful to understand:

  1. I run that problematic csd and play about 15 notes in polyphony.
  2. I press the STOP button to stop the performance.

Now, if I click on the PLAY button, Cabbage goes in crash but… If instead to click Play, I close the file by clicking on that little ‘x’ and then I reopen the same file and click Play, it doesn’t crash!
So, when you close a Csound file, I suppose you call some C/C++ code that does a “cleaner” release of the allocated resources… Is it possible?