Hi, pretty new to CSound.
I'm trying to create an opcode which takes an input k-rate frequency input, loops through a table of C Maj scale frequencies and returns the closest match.
I can't seem to get the looping to work, and I imagine its because I don't fully understand the implications of k-rate upon control flow, even though I've read the journal articles on the topic. (Control Flow parts I and II)
Below is my code, can someone take a look and let me know what I'm doing wrong. Also, anyone know an opcode that does pitch quantization already?
sr = 44100
kr = 1
nchnls = 1
; Takes a k-rate frequency and returns its closest member of a musical scale supplied as a table parameter
opcode pitchquant, k, ki
; take in parameters
k_freq, i_musical_table xin
k_index = 0
k_max = ftlen(i_musical_table)
k_dist = 0
k_last_dist = 999999999
k_output_index = 0
;loop through table
loopStart:
k_pitch_oct table k_index, i_musical_table, 0
k_pitch_freq = cpspch( k_pitch_oct )
k_dist = k_pitch_freq - k_freq
if( k_dist < k_last_dist ) then
k_last_dist = k_dist
k_output_index = k_index
endif
k_index = k_index + 1
if( k_index < k_max ) goto loopStart
;return output
k_out_pitch table k_output_index, i_musical_table, 0
k_pitch_freq = cpspch( k_out_pitch )
k_out = k_pitch_freq
xout k_out
endop
;tests the opcode above
instr 1
i_start = p2
i_desired_key = p4
k_freq = 440
k_freq_quant pitchquant k_freq, i_desired_key
printks "k_freq: %f k_freq_quant: %f\\n", 0, k_freq, k_freq_quant
endin



re: looping at the k-rate
Hmm... I'm actually not too sure why that doesn't work. What kind of output are you getting? What does your score look like?
Anyway, here's sort of an adaptation of a way I did this in Max. I tend to prefer to use MIDI note numbers, as it's more universal than Csound's octave.pitch way. This first converts the frequency to a MIDI note number (I don't think there's an opcode that converts frequency to MIDI [which is strange, I think], so I made a UDO that does it), then strips it down to a pitch class, rounds it, and uses it to index a table. The tables are filled with numbers corresponding to chromatic pitch classes. They range from C to C, and the idea is that if a note is chromatic to the scale, it rounds up. Hopefully the comments in the score will clarify that.
Just a side note, but is there any reason why you have kr = 1? 1 second seems like a long interval.
<CsoundSynthesizer>
<CsOptions>
</CsOptions>
<CsInstruments>
sr = 44100
ksmps = 128
nchnls = 2
0dbfs = 1
opcode Freq2MIDI, k, k
k_freq xin
;formula for converting frequency to MIDI note numbers
k_midinn = log(k_freq/261.626)/log(2)*12+60
xout k_midinn
endop
instr 1
i_key = p4
k_freq = 261.666 ;slightly sharp C
;NOTE: it would be more efficient to use Freq2MIDI to fill a
;look-up table than to run logs on every k-pass
k_midinn Freq2MIDI k_freq
k_octave = int(k_midinn/12)
k_pitch_class = k_midinn%12
k_pitch_class = int(k_pitch_class+.5) ;add .5 to round
k_pitch_class2 table k_pitch_class, i_key
k_freq_quant = cpsmidinn(k_octave*12+k_pitch_class2)
printks "k_freq: %f, k_freq_quant: %f\\n", .5, k_freq, k_freq_quant
endin
</CsInstruments>
<CsScore>
; 0 1 2 3 4 5 6 7 8 9 10 11 12
; c c# d d# e f f# g g# a a# b c
f 1 0 16 -2 0 2 2 4 4 5 7 7 9 9 11 11 12 ;C Major / A minor
f 2 0 16 -2 1 1 2 4 4 6 6 7 9 9 11 11 13 ;D Major / B minor
;etc.
i 1 0 1 1
e
</CsScore>
</CsoundSynthesizer>