Cabbage Logo
Back to Cabbage Site

Returning to CsoundUnity and updating old project

hi @rorywalsh - Happy new year to you! it’s taken a bit of time on my end to figure out how to approach triggering the correct row but i think i have figured it out now.

at the moment i’m currently triggering the EnableCubeToPlaySound function on the LayerController. this is the same code triggered by the layer playheads. here’s the code for that function:

public void EnableCubeToPlaySound(int row, int index, bool state)
{	
	if(enableLayer)
	{
		row = row +1;
		string channel = "rowCubeIndex"+row;
		csound.SetChannel(channel, index);
		channel = "rowCubeState"+row;
		if (state==true)
		{
			csound.SetChannel(channel, posIntensity[index]);
		}
		else if (state == false)
		{
			csound.SetChannel(channel, 0);	
		}
		channel = "rowCubeNote"+row;
		//get note plus modifier
		csound.SetChannel(channel,noteRowList[index]+transpose);
		
	}
}

so i think the function doesn’t seem too difficult. i can pretty easily call it outside of that function, but perhaps i should set a different channel rather than the one indicated here?

also an interesting bug/behavior i’ve run into that has been present for nearly all of the time i’ve been working on this new version - the first runthrough of any layer when playback is enabled will be silent, or perhaps only play the first note, but by the second repeat it will respond correctly. it’s a bit weird but seems consistent. it hasn’t bothered me much yet especially on tracks that are running with faster rhythmic values but on slower tempo relationships it can mean several seconds of silence before that layer plays. and it might be the reason the notes aren’t currently being triggered manually either when interacted with.

anyway, any help appreciated - as always!

Why, what are you concerned about?

Ouch. Sounds like a timing/update issue?

well, i’m not that concerned about using that function but it does need to respond in real-time and if there’s a timing/update issue preventing that (and also potentially causing the delay) then it seems like i need to address this. but the Csound script i’m using has hardly changed from the original example i got from you 8 years ago ( :open_mouth:!!!), other than it uses 16 steps and not 8.

let me check my early test examples using 8 x 8 grids…
hmm - so it seems to work fine, although it starts up playing automatically. so i disabled CsoundUnity and enabled my cubes and then enabled CsoundUnity and it played just fine.

so one of the script additions i made was to allow a boolean to enable playback and i did that by setting tempo to 0 when disabled and 60bpm when enabled. but i don’t think that is the problem here.

seems like i need to make a test single grid of 16x16 with my sequencer grid as an example and run that and see if there’s a delay. trying for a bit of a feature sprint in front of a demo at a meetup but i think fixing this bug may take a back seat to adding a few more features.

Are you trying to pin this problem on me :rofl: But there could well be an issue there. I don’t think I ever really tested that code. It was more of a push in the right direction…

1 Like

no sorry, i’m pretty sure i backed myself into this corner. the 8x8x8 version back in 2017 worked fine and had no delay and neither do these grid demos so it seems like its something i added to the CSD script or more likely in my handling of the script. you’re off the hook! i think…

I’m sure you realised I was only joking, but just in case, I was only joking! Could it be that when you enable a sequence and update a channel, it’s somehow being missing by Csound, until things come around again. I can’t quite remember how this is implemented, but can sequences be enabled at any point, or are they fixed to only start at the beginning?

yeah i know - no worries :grin:

so, technically they can be started at any point. practically, they should start at a negative position to the left of the first column to allow starting at zero. as i recall starting at zero in the past would automatically not play the first event so that’s how i managed it. but i have been able to pause and unpause playback from anywhere and once it has played the sequence it will keep playing even when pausing and unpausing.

but your guess of Csound missing the first pass sounds plausible.

okay @rorywalsh i think there’s a bit of an issue besides the latency going on here. i’ve been testing things and it looks like pausing and playback aren’t working as i had hoped. i created a bool to enable and disable that controls playback but what i’d like it to do is reset position when i resume playback, in an attempt to synchronize things. i’m sure that there’s a deeper amount of work to do but let’s start here with my C# code:

if(enableLayer)
	{
		if(currentBeat == csound.GetChannel("beat"))
		{
			//ResizeCubesInRow(currentBeat);
			position = currentBeat;
			_playbar.MovePosition(currentBeat);	
			currentBeat = (currentBeat != seqLength-1 ? currentBeat+1 : 0);
		
		}
	}
	else if(!enableLayer)
	{	
		tempTempo = masterTempo;
		masterTempo = stopTempo;
		currentBeat = 0;
		position = 0;
		csound.SetChannel("beat",0);	
		csound.SetChannel("tempo",0.0f);

	}

this is all wrapped into Update(). so here’s what happens - playback starts at position 0, and wraps back around after position 15. and if i disable the enableLayer bool for playback the sequence does stop. however, re enabling the playback bool continues to play back the sequence from the stopped point. it doesn’t rewind to zero. interestingly i have managed to get the playbar to rewind back to zero, but then it will sit there until the sequence finishes out and then it will pick up and start moving again.

so it seems Csound doesn’t get the message even though it looks like i’m telling beat to be at position 0 in the disabled code block.

also just as an experiment i commented out the tempo=0.0 call and then Csound just continued to play with nothing actually triggering the notes via the playbar. so the notes make it into Csound but not sure what exactly is causing the delay.

anyway, i just want to see if i can force Csound to rewind and play from the beginning after a pause. as always appreciate the help!

It’s hard to say what might be causing the problem. A few well placed print statement in your Csound code would help debug this. What happens if you set the beat position to -1? Maybe it’s the order of the incrementing?

I don’t see anything wrong in your C# code, so we must first ensure that Csound receives those messages.
Can you show us the relevant part that gets the “beat” and “tempo” channels in your csd?
Are they only defined in the Cabbage section?

as far as i can tell, almost nothing is set up in the Cabbage section. it’s all in Csound. here’s the ROW SEQUENCER code:

instr ROW_SEQUENCER

;each Row will take one of these notes and use it when a beat is enabled
;notes - modifiable by Layer control script (LayerController)
;C major scale by default ()
kNoteValues[] fillarray 48, 50, 52, 53, 55, 57, 59, 60, 62, 64, 65, 67, 69, 71, 72, 74
;amps - 0 by default. changed by cube state
kNotesAmps[] fillarray 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0

;run through note amps array and trigger note if amp is set to 1/on
kBeat init 0
kTempo chnget "tempo"
kInst chnget "inst"
kPreset chnget "sfPreset"
kSeqLength chnget "seqLength"
kDur chnget "duration"
kOffset chnget "noteOffset"
kNoteList chnget "noteRowList"



if metro(kTempo) != 0 then
	;if amplitude/vel is greater than 0, set event
	if kBeat < 16 then
		if kNotesAmps[kBeat] != 0 then
			if kInst == 0 then
				event "i", "inst0", 0, kDur, kNoteValues[p4-1]+kOffset,kNotesAmps[kBeat]		
			elseif kInst == 1 then
				event "i", "inst1", 0, kDur, kNoteValues[p4-1]+kOffset,kNotesAmps[kBeat]
			elseif kInst == 2 then
				event "i", "inst2", 0, kDur, kNoteValues[p4-1]+kOffset,kNotesAmps[kBeat]
			elseif kInst == 3 then
				event "i", "inst3", 0, kDur, kNoteValues[p4-1]+kOffset,kNotesAmps[kBeat]
			elseif kInst == 4 then
				event "i", "inst4", 0, kDur, kNoteValues[p4-1]+kOffset,kNotesAmps[kBeat]
			elseif kInst == 5 then
				event "i", "inst5", 0, kDur, kNoteValues[p4-1]+kOffset,kNotesAmps[kBeat]
			elseif kInst == 6 then
				event "i", "inst6", 0, kDur, kNoteValues[p4-1]+kOffset,kNotesAmps[kBeat]
			elseif kInst == 7 then
				event "i", "inst7", 0, kDur, kNoteValues[p4-1]+kOffset,kNotesAmps[kBeat]
			endif
			;printks "amps %d, %d, %d, %d, %d, %d, %d, %d", 0, kNotesAmps[0],kNotesAmps[1],kNotesAmps[2],kNotesAmps[3],kNotesAmps[4],kNotesAmps[5],kNotesAmps[6],kNotesAmps[7]
		endif	
	endif
	;set next beat if less than seqLength
	chnset kBeat, "beat"
	;advance kBeat if less than seqLength - otherwise reset count
	kBeat = (kBeat<kSeqLength-1 ? kBeat+1 : 0)
elseif metro(kTempo) == 0 then
kBeat init 0
endif

;get row number and create unique channel name
SRowCubeIndex sprintf "rowCubeIndex%d", p4
SRowCubeState sprintf "rowCubeState%d", p4
SrowCubeNote sprintf "rowCubeNote%d",p4
kCubeIndex chnget SRowCubeIndex
kCubeState chnget SRowCubeState
kCubeNote chnget SrowCubeNote

;if user has enabled a note, update note amp array
kChanged changed kCubeState, kCubeIndex
if changed(kChanged) > 0 then
	kNotesAmps[kCubeIndex] = kCubeState
	kNoteValues[kCubeIndex] = kCubeNote
	;printks "Updating row %d - index: %d - value: %d - note: %d - inst: %d",0, p4, kCubeIndex,kNotesAmps[kCubeIndex],kNoteValues[kCubeIndex],kInst
endif

hope that’s not too much code to sift through…

It looks like you are only ever updating "beat" from Csound. When you update "beat" in C#, your Csound code isn’t picking it up. I see no chnget "beat" anywhere…

interesting - so where would i put the chnget statement? can i stick it over here?:

elseif metro(kTempo) == 0 then
chnget "beat"
endif

that seems like a point where i would set the pointer of “beat”. is this right?

If you want to set the beat position in Csound, you need to set kBeat. You’re already setting a channel called “beat” in C#, but you don’t get this value in your Csound code. To get the “beat” value you need to do:

kBeat chnget "beat"

somewhere in your code. Otherwise kBeat will never be updated. chnget "beat" without a return value will just cause an error.

okay thanks! - got it. Csound uses the kBeat identifier so both it and the "beat’ need to be in the statement.

so it seems like that block is a good place to try putting it in. i’m on my work day today so i’ll try this out tonight after i’m done doing various tasks. appreciate this!

allright that had pretty much the same effect as me setting “beat” at 0, meaning it doesn’t work and just repeats the 0 position. but i am changing the tempo to not be zero when i enable playback. and yet somehow that doesn’t matter?

i also tried kBeat chnget “beat” at the top and it also repeatedly played a note - i think it may have been the last note in the sequence.

it seems like Csound is setting the position exclusively and NOT Unity. if i use Unity to set the position via "beat’ it doesn’t seem to work correctly. or rather it just seems to take over, playing one note/position and not advancing in Csound. the code block in Unity is under Update so it is continuous, but it changes back to a non zero tempo when the bool is enabled.

i guess what i need is a temporary pointer redirect and not a continuous one, like an event that only gets called once rather than every frame? either way it seems like kBeat gets updated to just stay at the same index. i’ll keep working on this, but this is definitely beyond my meager Csound knowledge currently.

Update - okay got it working. the issue was that i had to paste the incrementer code into the elseif block, so now i have:

elseif metro(kTempo) == 0 then
	kBeat chnget "beat"
	kBeat = (kBeat<kSeqLength-1 ? kBeat+1 : 0)

bit weird to me but i’ll take it. also i did have to set beat at -1 in the Unity C# side so it would play 0 after that.

so it looks like that’s solved. thanks for the pointers! now we just need to figure out the issue with the total silence on the first pass. let me share the current EnableCubeToPlaySound. this was adapted from your earlier script:

    public void EnableCubeToPlaySound(int row, int index, bool state)
	{	
		if(enableLayer)
		{
			row = row +1;
			string channel = "rowCubeIndex"+row;
			csound.SetChannel(channel, index);
			channel = "rowCubeState"+row;
			if (state==true)
			{
				csound.SetChannel(channel, posIntensity[index]);
			}
			else if (state == false)
			{
				csound.SetChannel(channel, 0);	
			}
			channel = "rowCubeNote"+row;
			//get note plus modifier
			csound.SetChannel(channel,noteRowList[index]+transpose);
			
		}
	}

one thing i found a bit weird but i have no idea if it contributes is the use of the string channel where its reassigned several times to set different things in Csound. just FYI i have colliders on every row parented to an object that moves horizontal position based on what it gets from Csound. so that’s 16 colliders marching across looking for enabled stars/events and all of them phoning into this function.

The above script will set the same channel in the same Unity frame 3 times, with 3 different values. Is this what you want?
I guess the channel value will be overridden in Csound (so it will always have a value of noteRowList[index]+transpose)

Edit:
Sorry I misread, it should be ok! You’re changing the string channel value :man_facepalming:

Ha, I misread it the exact same way a few weeks back when @metaphysician first posted it :rofl:

As for the issue, you really need to add some print statements to your Csound code so you can see what’s going on. Otherwise it’s all guess work.

1 Like

okay - agreed on the print statements. where should i be putting them on the code? there are some already there i think. that’s this one:

if changed(kChanged) > 0 then
	kNotesAmps[kCubeIndex] = kCubeState
	kNoteValues[kCubeIndex] = kCubeNote
	;printks "Updating row %d - index: %d - value: %d - note: %d - inst: %d",0, p4, kCubeIndex,kNotesAmps[kCubeIndex],kNoteValues[kCubeIndex],kInst
endif

where else should i be putting these?