From 9fbf91db06a6d4f4b5cd8bb45389a731bb86bf22 Mon Sep 17 00:00:00 2001 From: Richard Date: Sun, 13 Apr 2025 18:48:02 +0100 Subject: initial --- site/udo/sequencing_melodic_portamento.udo | 310 +++++++++++++++++++++++++++++ 1 file changed, 310 insertions(+) create mode 100755 site/udo/sequencing_melodic_portamento.udo (limited to 'site/udo/sequencing_melodic_portamento.udo') diff --git a/site/udo/sequencing_melodic_portamento.udo b/site/udo/sequencing_melodic_portamento.udo new file mode 100755 index 0000000..fe3bde2 --- /dev/null +++ b/site/udo/sequencing_melodic_portamento.udo @@ -0,0 +1,310 @@ +#ifndef UDO_MELSEQUENCINGPORT +#define UDO_MELSEQUENCINGPORT ## + +/* + Extension to sequencing_melodic.udo which permits usage of k-rate frequency arrays + + This file is part of the SONICS UDO collection by Richard Knight 2021 + License: GPL-2.0-or-later + http://1bpm.net +*/ + +#include "__config__.udo" ; using fftsize for tuning +#include "sequencing_melodic.udo" +#include "wavetables.udo" +#include "frequency_tools.udo" + + +gimel_freqs ftgen 0, 0, -12, -7, 0 ; current notes: index 0 is the length +gimel_amps ftgen 0, 0, -12, -7, 0 ; current notes: index 0 is the length + +gimel_portamento_beatratio init 0.5 ; portamento time as ratio of current beat time +gimel_linetype init 0 ; 0=pre-section, 1=post-section + + +/* + Automate a frequency/amp line +*/ +instr _mel_linedraw + index = p4 + ifreq = p5 + iamp = p6 + + icurrentfreq table index, gimel_freqs + + if (icurrentfreq == 0 && ifreq != 0) then + tablew ifreq, index, gimel_freqs + elseif (ifreq != 0 && icurrentfreq != ifreq) then + tablew line:k(icurrentfreq, p3, ifreq), index, gimel_freqs + endif + + icurrentamp table index, gimel_amps + if (icurrentamp != iamp) then + tablew line:k(icurrentamp, p3, iamp), index, gimel_amps + endif +endin + + +instr _mel_linestep_inner + if (timeinstk() == 1) then + turnoff2 "_mel_linedraw", 0, 0 + endif + + if (table:i(1, gimel_next_notes) != 0) then + index = 0 + while (index < table:i(0, gimel_next_notes)) do + event_i "i", "_mel_linedraw", 1/kr, p3, index, cpsmidinn(table:i(index + 1, gimel_next_notes)), 1 + index += 1 + od + while (index < ftlen(gimel_freqs)) do + event_i "i", "_mel_linedraw", 1/kr, p3, index, 0, 0 + index += 1 + od + endif +endin + + +instr _mel_linestep + icurrentduration mel_length + ilinetime = (i(gkseq_beattime) * gimel_portamento_beatratio) + if (gimel_linetype == 0) then + inextline = icurrentduration - ilinetime + else + inextline = icurrentduration + endif + event_i "i", "_mel_linestep_inner", inextline, ilinetime + turnoff +endin + + +/* + Portamento manager: respond to gkmel_section_change trigger by calling _mel_linestep instrument +*/ +instr _mel_linemanager + ; set initial freqs + index = 0 + while (index < table:i(0, gimel_current_notes)) do + tablew cpsmidinn(table:i(index + 1, gimel_current_notes)), index, gimel_freqs + tablew 1, index, gimel_amps + index += 1 + od + while (index < ftlen(gimel_freqs)) do + tablew 0, index, gimel_amps + index += 1 + od + + schedkwhen gkmel_section_change, 0, 1, "_mel_linestep", 0, 1 +endin + +schedule "_mel_linemanager", 0.1, 36000 ; notes not ready on 0 +;alwayson "_mel_linemanager" + + + + + +/* + Recursively create a chord to be used by mel_tune_portamento; internal use only + + aout _mel_tune_chord_portamento kfreqmult, ifn, imaxmult, imult, index + + aout chord output + kfreqmult frequency multiplier to apply to tuning + ifn wavetable to use + imaxmult multiples of harmonics to generate in tuning + imult internal multiplier for recursion + index internal index for recursion + +*/ +opcode _mel_tune_chord_portamento, a, kiipo + kfreqmult, ifn, imaxmult, imult, index xin + + + if (index + 1 > ftlen(gimel_amps)) then + index = 0 + imult += 1 + endif + + aout = oscil(table:k(index, gimel_amps), kfreqmult * table:k(index, gimel_freqs) * pow:k(2, imult), ifn) * 0.1 + ; recursion for all chord parts + if (imult <= imaxmult) then + aout += _mel_tune_chord_portamento(kfreqmult, ifn, imaxmult, imult, index + 1) + endif + + xout aout +endop + + + +/* + PVS morph tuning to current melodic sequencer notes + aoutL, aoutR mel_tune_portamento ainL, ainR, [ifn=gifnSine, imult=4, ifftrate=giFFTsize, ifftdiv=giFFTwinFactor, kfreqmult=1] + + aoutL, aoutR output audio + ainL, ainR input audio + ifn wavetable to use + imaxmult multiples of harmonics to generate in tuning (defaults to 4) + ifftrate fft size, defaults to config default + ifftdiv fft window division factor (eg 4, 8, 16), defaults to config default + kfreqmult frequency multiplier to apply to tuning +*/ +opcode mel_tune_portamento, aa, aaooooP + aL, aR, ifn, imaxmult, ifftrate, ifftdiv, kfreqmult xin + ifn = (ifn == 0) ? gifnSine : ifn + imaxmult = (imaxmult == 0) ? 4 : imaxmult + ifftrate = (ifftrate == 0) ? giFFTsize : ifftrate + ifftdiv = (ifftdiv == 0) ? giFFTwinFactor : ifftdiv + fmods pvsanal _mel_tune_chord_portamento(kfreqmult, ifn, imaxmult), ifftrate, ifftrate/ifftdiv, ifftrate, 1 + fL1 pvsanal aL, ifftrate, ifftrate/ifftdiv, ifftrate, 1 + fR1 pvsanal aR, ifftrate, ifftrate/ifftdiv, ifftrate, 1 + fL2 pvsmorph fL1, fmods, 0, 1 + fR2 pvsmorph fR1, fmods, 0, 1 + aL1 pvsynth fL2 + aR1 pvsynth fR2 + idel = (ifftrate)/sr + aL1 balance aL1, delay(aL, idel) + aR1 balance aR1, delay(aR, idel) + xout aL1, aR1 +endop + + +/* + Bandpass tuning for internal use only, applied to each note frequency for full spectrum bandpass + + aoutL, aoutR _mel_bandpass_portamento_freqgroup ainL, ainR, kfreq, kbw, iprecise, imult + + aoutL, aoutR output audio + ainL, ainR input audio + kfreq frequency to tune to + kbw bandwidth of bandpass filters + iprecise if 1, use two serial bandpass filters for more precision + imult current multiplier for recursion +*/ +opcode _mel_bandpass_portamento_freqgroup, aa, aakkip + ainL, ainR, kfreq, kbw, iprecise, imult xin + imaxmult = 24 + + aoutL butterbp ainL, kfreq*imult, kbw + aoutR butterbp ainR, kfreq*imult, kbw + + if (iprecise == 1) then + aoutL butterbp aoutL, kfreq*imult, kbw + aoutR butterbp aoutR, kfreq*imult, kbw + endif + + if (imult <= imaxmult) then + aoutLrec, aoutRrec _mel_bandpass_portamento_freqgroup ainL, ainR, kfreq, kbw, iprecise, imult * 2 + aoutL += aoutLrec + aoutR += aoutRrec + endif + xout aoutL, aoutR +endop + + +/* + Bandpass tuning to current melodic sequencer notes + + aoutL, aoutR mel_bandpass_portamento ainL, ainR [, kbw=1, iprecise=0, index=0] + + aoutL, aoutR output audio + ainL, ainR input audio + kbw bandwidth of bandpass filters + iprecise if 1, use two serial bandpass filters for more precision + index recursion index for internal use +*/ +opcode mel_bandpass_portamento, aa, aaPoo + ainL, ainR, kbw, iprecise, index xin + kamp = table:k(index, gimel_amps) + + if (kamp > 0) then + kfreq = table:k(index, gimel_freqs) + aoutL, aoutR _mel_bandpass_portamento_freqgroup ainL, ainR, kfreq, kbw, iprecise + aoutL *= kamp + aoutR *= kamp + else + aoutL = 0 + aoutR = 0 + endif + + if (index < ftlen(gimel_amps)) then + aoutLr, aoutRr mel_bandpass_portamento ainL, ainR, kbw, iprecise, index + 1 + aoutL += aoutLr + aoutR += aoutRr + endif + xout aoutL, aoutR +endop + + + +/* + Ringmod tuning to current melodic sequencer notes + aoutL, aoutR mel_ringmod_portamento ainL, ainR kfreqmult, index + + aoutL, aoutR output audio + ainL, ainR input audio + kfreqmult frequency multiplier to apply to current frequencies + index recursion index for internal use +*/ +opcode mel_ringmod_portamento, aa, aaPo + ainL, ainR, kfreqmult, index xin + + kamp = table:k(index, gimel_amps) + + if (kamp > 0) then + aoutL, aoutR ringmod1 ainL, ainR, table:k(index, gimel_freqs) * kfreqmult + aoutL *= kamp + aoutR *= kamp + else + aoutL = 0 + aoutR = 0 + endif + + if (index < ftlen(gimel_amps)) then + aoutLr, aoutRr mel_ringmod_portamento ainL, ainR, kfreqmult, index + 1 + aoutL += aoutLr + aoutR += aoutRr + endif + xout aoutL, aoutR +endop + + + +/* + Reson tuning to current melodic sequencer notes + + aoutL, aoutR mel_reson_portamento ainL, ainR kfreqmult, index + + aoutL, aoutR output audio + ainL, ainR input audio + kfreqmult frequency multiplier to apply to current frequencies + index recursion index for internal use +*/ +opcode mel_reson_portamento, aa, aaPo + ainL, ainR, kfreqmult, index xin + + kamp = table:k(index, gimel_amps) + kfreq = table:k(index, gimel_freqs) + + if (kamp > 0) then + aoutL resony ainL, kfreq * kfreqmult, 2, 8, 10 + aoutR resony ainR, kfreq * kfreqmult, 2, 8, 10 + aoutL balance aoutL, ainL + aoutR balance aoutR, ainR + aoutL *= kamp + aoutR *= kamp + else + aoutL = 0 + aoutR = 0 + endif + + if (index < ftlen(gimel_amps)) then + aoutLr, aoutRr mel_reson_portamento ainL, ainR, kfreqmult, index + 1 + aoutL += aoutLr + aoutR += aoutRr + endif + xout aoutL, aoutR +endop + + +#end + -- cgit v1.2.3