#ifndef UDO_MELSYS #define UDO_MELSYS ## /* Melodic sampler system Typical external usage should only refer to mel_playnote mel_getcollection This file is part of the SONICS UDO collection by Richard Knight 2021 License: GPL-2.0-or-later http://1bpm.net */ #include "sound_db.udo" #include "pgdb.udo" #include "host_tools.udo" #include "pvs_tools.udo" #include "bussing.udo" opcode _mel_loadobject, i[][], S[][] Sres[][] xin imelmap[][] init 128, 16 index = 0 while (index < lenarray(Sres)) do ifileid strtod Sres[index][0] ichannels strtod Sres[index][2] iduration strtod Sres[index][3] inote strtod Sres[index][4] if (imelmap[inote][0] == 0) then imelmap[inote][0] = 1 endif imelmap[inote][imelmap[inote][0]] _rdb_loadsound ifileid, ichannels, iduration, Sres[index][1] imelmap[inote][0] = imelmap[inote][0] + 1 ; first index keeps track of length index += 1 od xout imelmap endop /* Get soundcollection with basic analysis information isounds[][] getcollection ScollectionName isounds[][] soundcollection object ScollectionName the name of the filecollection in the database */ opcode mel_getcollection, i[][], S Scollection xin Sbase = {{select file_id, f_localpath(%d, path), channels, duration, note from svw.analysis_basic_collectionnorm a join filecollection fc on fc.id = a.filecollection_id join filecollectiontype fct on fct.id = fc.type_id where fc.name = '%s' and fct.name = 'melsys' }} Squery sprintf Sbase, gihost_type, Scollection Sres[][] dbarray gidb, Squery idata[][] _mel_loadobject Sres xout idata endop /* Get all melodic soundcollection names Scollections[] mel_listcollections Scollections[] list of soundcollections */ opcode mel_listcollections, S[], 0 Sres[][] dbarray gidb, "select distinct fc.name from filecollection fc join filecollectiontype fct on fct.id = fc.type_id where fct.name = 'melsys'" ilen = lenarray(Sres) Scollections[] init ilen index = 0 while (index < ilen) do Scollections[index] = Sres[index][0] index += 1 od xout Scollections endop /* Get nearest note and a ratio to alter to specific note */ opcode _mel_getnearestnote, ii, ii[][] inote, imelmap[][] xin iratio = 0 inearest = -1 idistance = 999 index = 0 while (index < 128) do if (imelmap[index][0] > 0) then if (inote > index) then imeasure = inote - index if (imeasure < idistance) then idistance = imeasure inearest = index endif elseif (inote < index ) then imeasure = index - inote if (imeasure < idistance) then idistance = imeasure inearest = index endif else idistance = 0 inearest = inote goto output endif endif index += 1 od iratio = cpsmidinn(inote) / cpsmidinn(inearest) output: isoundindex = imelmap[inearest][int(random(1, imelmap[inearest][0]))] xout isoundindex, iratio endop opcode mel_getrandnote, ii, ii[][] inote, imelmap[][] xin iout = -1 if (imelmap[inote][0] > 0) then index = int(random(1, imelmap[inote][0])) iout = imelmap[inote][index] iratio = 1 else iout, iratio _mel_getnearestnote inote, imelmap endif xout iout, iratio endop /* */ opcode _mel_playsound, 0, iSppooooo index, Sbus, iamp, ipitchratio, iwhen, iusepvs, ikeepformant, ifadein, idurationoverride xin Scoreline = sprintf("i\"mel_player_default\" %f 1 \"%s\" %f %f %f %d %d %d %f", iwhen, Sbus, index, iamp, ipitchratio, iusepvs, ikeepformant, ifadein, idurationoverride) scoreline_i Scoreline endop opcode mel_playnote, 0, i[][]iSpooooo imelmap[][], inote, Sbus, iamp, iwhen, idurationoverride, iusepvs, ikeepformant, ifadein xin isoundindex, ipitchratio mel_getrandnote inote, imelmap _mel_playsound isoundindex, Sbus, iamp, ipitchratio, iwhen, iusepvs, ikeepformant, ifadein, idurationoverride endop instr mel_player_default Sbus = p4 isoundindex = p5 iamp = p6 ipitchratio = p7 iusepvs = p8 ikeepformant = p9 ifadein = p10 idurationoverride = p11 isound[] = get_sound(isoundindex) if (idurationoverride == 0) then p3 = isound[3] ; set duration else p3 = idurationoverride endif if (iusepvs == 1) then iloscilratio = 1 else iloscilratio = ipitchratio endif if (isound[2] == 1) then ; check channels aL loscil iamp, iloscilratio, isound[0], 1 if (iusepvs == 1) then aL pvscaler aL, ipitchratio, ikeepformant endif aR = aL else aL, aR loscil iamp, iloscilratio, isound[0], 1 if (iusepvs == 1) then aL pvscaler aL, ipitchratio, ikeepformant aR pvscaler aR, ipitchratio, ikeepformant endif endif if (ifadein == 1) then kenv linseg 0, p3*0.4, 1, p3*0.5, 1, p3*0.1, 0 else kenv linseg 1, p3*0.9, 1, p3*0.1, 0 endif bus_mix(Sbus, aL*kenv, aR*kenv) endin #end