Cabbage Logo
Back to Cabbage Site

Looping constructions

Hi all,

Below is my attempt to generate a random melody between 7 and 13 notes. The algorithm seemed to be running fine for the most part, but the loop itself ran twice, once because it ran the loop as any piece of code would run(…“initial pass?”), and another time because of the metro object which “reinit” the loop.

The solution I have at the moment is to delay the metro by the same interval by which it itself is defined, so that I can start the periodic execution of the algorithm a little later. I was wondering if anyone had a better solution. Or am I not understanding the loop_lt opcode correctly?

random melody gen.csd (1.4 KB)

I haven’t used that opcode before, but I would suggest using these new Cabbage midi-opcodes for building this. They are pretty great and the implementation is simple :+1:

I wouldn’t use the loop opcode and reinit for this. There are simpler ways to generate a random melody of 7 to 13 notes. I will be back at my PC in a few days, I can send some code then. Reinit frightens me :rofl: I always prefer to avoid it where I can!

There’s many ways to loop melodies. As per Rory’s suggestion of avoiding reinit, one simple way to modify your existing code would be to seperate the metro from the mother instr.

event_i "i", "metro", 0, 1000

instr metro
ifreq=20 ; freq. of metro trigger in seconds
kmetro  metro 1/ifreq
printk2(kmetro)
schedkwhen kmetro, 0, 0, "mother", 0, .1

endin

instr mother

	inotes random 7, 13
	ininstr = round(inotes)
	print ininstr
	indx=0
					
	loop1:
					
	  irand random 1, 2
	  ifreq random 440, 880
	  iamp  random 0.01, 1
		event_i "i", 1, indx+irand, 1+irand, ifreq*irand, iamp
	loop_lt indx, 1, ininstr, loop1
								
endin

This of course replays the random melody at intervals of 20 seconds (metro 1/ifreq), but that would be easy to randomize as well with something like:

instr metro
; randomize metro rate between 16 sec.
; to 26 seconds
kinter randomh 16, 26, 1/16
kmetro metro 1/kinter

I find it interesting to see how others achieve something similiar using different methods. Generally I don’t use the loop opcodes either but thought perhaps modifying your code might be interesting since you’re already comfortable with it.

Thanks very much for all your responses!

@hdale94, not sure how I would use that particular opcode since I’m not dealing with any MIDI data. What did you have in mind?

@rorywalsh I see! I studied computer science in high school and so for loops seemed like a intuitive place for me to start. I’m looking forward to your solution!

@ST_Music Thanks very much for the modification! I have been reluctant to see how schedkwhen works but it seems pretty straightforward. I had no clue this “randomh” opcode existed, I should definitely see how it works, and use it for some other stuff. Thanks also for not revising the code too much! As mentioned above this method just seemed kind of intuitive to me so that’s what I ended up doing.

That’s true, I thought it would be triggered by midi, but I see that’s not the case :+1:

On the other hand, if you had created your loops as short midi files you could easily loop through them, but I think the proposal by @ST_Music is a good one. I’ve never been a fan of the looping opcodes though. I’d probably use a while loop instead as I find it more readable, but the outcome would be the same.

Hi @rorywalsh. I’m curious - I’m not great with recursion but have been toying with that, both in instr & UDO’s, as a way to loop certain things. Sometimes successfully, others not so much. Most likely due to lack of experience.

In this scenario do you think it might be an option?

Yes, but I guess you could just use a recursive instrument (not really tested!):

<Cabbage>
form size(500, 300), caption("Untitled"), pluginId("asd3")
</Cabbage>
<CsoundSynthesizer>
<CsOptions>
</CsOptions>
<CsInstruments>
nchnls = 2
0dbfs = 1

instr 1
    //choose the number on notes on fist run...
    if p5<0 then
	    p5 = random(2, 4)
	endif
	    
	iNotes = round(p5)
	print iNotes, p4
	indx=p4		
	irand random 1, 2
	ifreq random 440, 880
	iamp  random 0.01, 1
    event_i "i", 2, indx+irand, 1+irand, ifreq*irand, iamp
    
    //if indx is less than number of notes, call instr 1 again
    //otherwise, if p4==iNotes start the whole thing again
	if p4 < iNotes then
	    schedule(1,0,0,indx+1, p5)
	endif
	
	if p4 == iNotes then
	    prints "Starting entire sequence again"
	    schedule(1,indx+irand,0,0,-1)
	endif
endin

instr 2
    print p1, p2, p3, p4, p5
endin

</CsInstruments>
<CsScore>
f1 0 1024 10 1
i1 0 35 200 1
i1 0 0 0 -1
</CsScore>
</CsoundSynthesizer>