From 9fbf91db06a6d4f4b5cd8bb45389a731bb86bf22 Mon Sep 17 00:00:00 2001 From: Richard Date: Sun, 13 Apr 2025 18:48:02 +0100 Subject: initial --- site/udo/sound_sdb.udo | 271 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100755 site/udo/sound_sdb.udo (limited to 'site/udo/sound_sdb.udo') diff --git a/site/udo/sound_sdb.udo b/site/udo/sound_sdb.udo new file mode 100755 index 0000000..82fe009 --- /dev/null +++ b/site/udo/sound_sdb.udo @@ -0,0 +1,271 @@ +#ifndef UDO_SOUNDSDB +#define UDO_SOUNDSDB ## +/* + SQL database interface to sound object management + + 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 "bussing.udo" +#include "host_tools.udo" +#include "pvs_tools.udo" + +/* + soundcollection object structure: 2D array with first dimension as sound index and second as + 0 runtime sound db index + 1 rms normalised over all collections + 2 average pitch hz + 3 average centroid hz + 4 match distance; optional depending on returning opcode +*/ + + + +;gisdb_data[][] init 99999, 4 + +/* + Internal: format a standard soundcollection database result as soundcollection object + isounds[][] _load_sdbobject Sresult[][], [ihasdistance] + + isounds[][] soundcollection object + Sresult[][] the raw database result string array + ihasdistance whether to include the additional distance dimension + +*/ + +opcode _sdb_loadobject, i[][], S[][]o + Sres[][], ihasdistance xin + iarraylength = lenarray(Sres) + idata[][] init iarraylength, 4 + ihasdistance + index = 0 + while (index < lenarray(Sres)) do + ifileid strtod Sres[index][0] + ichannels strtod Sres[index][2] + iduration strtod Sres[index][3] + idata[index][0] _rdb_loadsound ifileid, ichannels, iduration, Sres[index][1] + idata[index][1] strtod Sres[index][4] ; rmsnormal + idata[index][2] strtod Sres[index][5] ; pitch + idata[index][3] strtod Sres[index][6] ; centroid + if (ihasdistance == 1) then + idata[index][4] strtod Sres[index][7] + endif + index += 1 + od + xout idata +endop + + +/* + Get a string array of all current filecollections + Scollections[] sdb_listcollections + + Scollections[] list of collections +*/ +opcode sdb_listcollections, S[], 0 + Sres[][] dbarray gidb, "select name from filecollection" + ilen = lenarray(Sres) + Scollections[] init ilen + index = 0 + while (index < ilen) do + Scollections[index] = Sres[index][0] + index += 1 + od + xout Scollections +endop + + +/* + Get soundcollection(s) with basic analysis information + isounds[][] sdb_getcollection ScollectionName + + isounds[][] soundcollection object + ScollectionName the name of the filecollection in the database or comma separated list of collections +*/ + +opcode sdb_getcollection, i[][], S + Scollection xin + Sbase = {{select file_id, f_localpath(%d, path), channels, duration, rmsnormal, pitch, centroid + from svw.analysis_basic_collectionnorm a + join filecollection fc on fc.id = a.filecollection_id + where %s + }} + + if (strindex(Scollection, ",") > 0) then + Sclause = "(1=2" + index = 1 + Stemp = Scollection + while (index > 0) do + index strindex Stemp, "," + if (index > 0) then + Sclause strcat Sclause, sprintf(" or fc.name='%s'", strsub(Stemp, 0, index)) + Stemp strsub Stemp, index+1 + else + Sclause strcat Sclause, sprintf(" or fc.name='%s'", Stemp) + endif + od + Sclause strcat Sclause, ")" + else + Sclause = sprintf("fc.name = '%s'", Scollection) + endif + + Squery sprintf Sbase, gihost_type, Sclause + Sres[][] dbarray gidb, Squery + idata[][] _sdb_loadobject Sres + xout idata +endop + + + +/* + Bubble sort a soundcollection 'object' by a specified analysis element + iordered[][] orderby isounds[][], ielement, [isortorder=0] + + iordered[][] the sorted soundcollection 'object' + isounds[][] the input soundcollection 'object' + ielement which analysis element to order by: + 0 duration + 1 rms + 2 pitch + 3 centroid + 4 distance, if collection is provided from a matching opcode + isortorder optional sort order: + 0 descending + 1 ascending + +*/ +opcode sdb_orderby, i[][], i[][]io + idata[][], ielement, iordering xin + ilen = lenarray(idata) + index = 0 + while (index < ilen) do + index2 = 0 + while (index2 < ilen) do + ; duration requires an obnoxious looking cross array reference + if (\ + (ielement == 0 && ( \ + (iordering == 0 && gisoundsdb[idata[index][0]][3] > gisoundsdb[idata[index2][0]][3]) \ + || (iordering == 1 && gisoundsdb[idata[index][0]][3] < gisoundsdb[idata[index2][0]][3]) \ + )) || ( \ + (iordering == 0 && idata[index][ielement] > idata[index2][ielement]) \ + ||(iordering == 1 && idata[index][ielement] < idata[index2][ielement]) \ + ) \ + ) then + iswap[] getrow idata, index + iswap2[] getrow idata, index2 + idata setrow iswap2, index + idata setrow iswap, index2 + endif + index2 += 1 + od + index += 1 + od + xout idata +endop + + + + + + +/* + Filter a soundcollection object with min and max parameters of basic analysis data applied + ifiltered[][], ivalid subselect isounds[][], + [iminduration, imaxdur, iminrms, imaxrms, iminpitch, imaxpitch, imincent, imaxcent] + + ifiltered[][] the new soundcollection 'object' with sounds limited to scope specified + ivalid 1 if records returned, 0 if the returned array is effectively empty + isounds[][] the input soundcollection 'object' to be filtered + iminduration optional minimum duration + imaxduration optional maximum duration + iminrms optional minimum rms + imaxrms optional maximum rms + iminpitch optional minimum pitch + imaxpitch optional maximum pitch + imincent optional minimum centroid + imaxcent optional maximum centroid + +*/ +opcode sdb_subselect, i[][]i, i[][]iii + idata[][], ielement, imin, imax xin + + indexes[] init lenarray(idata) + imaxindex = 0 + index = 0 + + while (index < lenarray(idata)) do + if ( \ + idata[index][ielement] >= imin && idata[index][ielement] <= imax \ + ) then + indexes[imaxindex] = index + imaxindex += 1 + endif + index += 1 + od + + if (imaxindex == 0) then + ifiltered[][] init 1, 1 + ivalid = 0 + else + ifiltered[][] init imaxindex, 7 + ivalid = 1 + index = 0 + while (index < imaxindex) do ; TODO setrow here????? + index2 = 0 + while (index2 < 7) do + ifiltered[index][index2] = idata[indexes[index]][index2] + index2 += 1 + od + index += 1 + od + endif + xout ifiltered, ivalid +endop + + + + +opcode _sdb_playsound, 0, iSppoooo + index, Sbus, iamp, ihz, iwhen, iusepvs, ikeepformant, ifadein xin + Scoreline = sprintf("i\"sdb_player_default\" %f 1 \"%s\" %d %f %f %d %d %d", iwhen, Sbus, index, iamp, ihz, iusepvs, ikeepformant, ifadein) + scoreline_i Scoreline +endop + + +opcode sdb_playsound, 0, i[][]iSpooooo + isounds[][], index, Sbus, iamp, iwhen, ihz, iusepvs, ikeepformant, ifadein xin + _sdb_playsound isounds[index][0], Sbus, iamp, ihz, iwhen, iusepvs, ikeepformant, ifadein +endop + + +opcode sdb_playrandom, 0, i[][]Spooooo + isounds[][], Sbus, iamp, iwhen, ihz, iusepvs, ikeepformant, ifadein xin + index = round(random(0, lenarray(isounds)-1)) + _sdb_playsound isounds[index][0], Sbus, iamp, ihz, iwhen, iusepvs, ikeepformant, ifadein +endop + + +instr sdb_player_default + Sbus = p4 + isoundindex = p5 + iamp = p6 + ihz = p7 + iusepvs = p8 + ikeepformant = p9 + ifadein = p10 + isound[] = get_sound(isoundindex) + + p3 = isound[3] + + aL, aR loscil iamp, 1, isound[0], 1 + + kenv linseg 1, p3*0.9, 1, p3*0.1, 0 + + bus_mix(Sbus, aL*kenv, aR*kenv) +endin + +#end -- cgit v1.2.3