/* StrayNumToFt - Converts a string-array which just consists of numbers or simple math expressions to a function table DESCRIPTION Puts all numbers in Stray (which must not contain non-numerical elements) in a function table and returns its variable ift (which is produced by iftno, default=0) and the length of the elements written iftlen. (An empty string as input writes a function table of size=1 to avoid an error but returns 0 as length of elements written.) Simple binary math expressions using +, -, *, /, ^ and % are allowed, with just one parenthesis in total (see the examples below). Elements are defined by two seperators as ASCII coded characters: isep1 defaults to 32 (= space), isep2 defaults to 9 (= tab). If just one seperator is used, isep2 equals isep1. Requires csound 5.15 or higher, and the UDOs StrayLen, Stray1Expr and StrayExpr (code included here) SYNTAX ift, iftlen StrayNumToFt Stray [, iftno [, isep1 [, isep2]]] INITIALIZATION Stray - a string as array iftno - like in an ftgen statement: if 0 (which is also the default) an automatic number is generated by Csound; if any positive number, this is then the number of the function table isep1 - the first seperator (default=32: space) isep2 - the second seperator (default=9: tab) ift - the number of the function table which has been created iftlen - the length of the elements written to the function table (usually this equals the length of the function table; just an empty string as input will create a function table of size=1 but with iftlen=0) CREDITS joachim heintz april 2010 / sept 2011 / feb 2012 */ opcode StrayLen, i, Sjj Stray, isepA, isepB xin ;;DEFINE THE SEPERATORS isep1 = (isepA == -1 ? 32 : isepA) isep2 = (isepA == -1 && isepB == -1 ? 9 : (isepB == -1 ? isep1 : isepB)) Sep1 sprintf "%c", isep1 Sep2 sprintf "%c", isep2 ;;INITIALIZE SOME PARAMETERS ilen strlen Stray icount = 0; number of elements iwarsep = 1 indx = 0 if ilen == 0 igoto end ;don't go into the loop if String is empty loop: Snext strsub Stray, indx, indx+1; next sign isep1p strcmp Snext, Sep1; returns 0 if Snext is sep1 isep2p strcmp Snext, Sep2; 0 if Snext is sep2 if isep1p == 0 || isep2p == 0 then; if sep1 or sep2 iwarsep = 1; tell the log so else ; if not if iwarsep == 1 then ; and has been sep1 or sep2 before icount = icount + 1; increase counter iwarsep = 0; and tell you are ot sep1 nor sep2 endif endif loop_lt indx, 1, ilen, loop end: xout icount endop opcode Stray1Expr, i, S StrayEl xin isum strindex StrayEl, "+"; sum idif strindex StrayEl, "-"; difference ipro strindex StrayEl, "*"; product irat strindex StrayEl, "/"; ratio ipow strindex StrayEl, "^"; power imod strindex StrayEl, "%"; modulo if ipow > 0 then ifirst strindex StrayEl, "^" S1 strsub StrayEl, 0, ifirst S2 strsub StrayEl, ifirst+1 i1 strtod S1 i2 strtod S2 ires = i1 ^ i2 elseif imod > 0 then ifirst strindex StrayEl, "%" S1 strsub StrayEl, 0, ifirst S2 strsub StrayEl, ifirst+1 i1 strtod S1 i2 strtod S2 ires = i1 % i2 elseif ipro > 0 then ifirst strindex StrayEl, "*" S1 strsub StrayEl, 0, ifirst S2 strsub StrayEl, ifirst+1 i1 strtod S1 i2 strtod S2 ires = i1 * i2 elseif irat > 0 then ifirst strindex StrayEl, "/" S1 strsub StrayEl, 0, ifirst S2 strsub StrayEl, ifirst+1 i1 strtod S1 i2 strtod S2 ires = i1 / i2 elseif isum > 0 then ifirst strindex StrayEl, "+" S1 strsub StrayEl, 0, ifirst S2 strsub StrayEl, ifirst+1 i1 strtod S1 i2 strtod S2 ires = i1 + i2 elseif idif > -1 then ifirst strrindex StrayEl, "-";(last occurrence: -3-4 is possible, but not 3--4) S1 strsub StrayEl, 0, ifirst S2 strsub StrayEl, ifirst+1 iS1len strlen S1 if iS1len == 0 then ;just a negative number inum strtod S2 ires = -inum else ifirst strtod S1 isec strtod S2 ires = ifirst - isec endif else ires strtod StrayEl endif xout ires endop opcode StrayExpr, i, S Sin xin ilen strlen Sin ;if a parenthesis can be found iparenth strindex Sin, "(" if iparenth > -1 then ;if in first half if iparenth == 0 then ;then first element ends in ")" iprend strindex Sin, ")" S1 strsub Sin, 1, iprend ;convert this element into a number i1 Stray1Expr S1 ;append the rest and convert again S2 strsub Sin, iprend+2 Sep strsub Sin, iprend+1, iprend+2 Scoll sprintf "%f%s%s", i1, Sep, S2 ires Stray1Expr Scoll ;if the parenthesis in in the second half else ;isolate first element and the conjunction S1 strsub Sin, 0, iparenth-1 Sep strsub Sin, iparenth-1, iparenth ;convert the second element S2 strsub Sin, iparenth+1, ilen-1 i2 Stray1Expr S2 ;if subtraction and i2 negative, convert to addition isepminus strcmp Sep, "-" if i2 < 0 && isepminus == 0 then i2 = i2 * (-1) Sep = "+" endif ;convert the whole Scoll sprintf "%s%s%f", S1, Sep, i2 ires Stray1Expr Scoll endif ;if no parenthesis, simply convert else ires Stray1Expr Sin endif xout ires endop opcode StrayNumToFt, ii, Sojj Stray, iftno, isepA, isepB xin ;;DEFINE THE SEPERATORS isep1 = (isepA == -1 ? 32 : isepA) isep2 = (isepA == -1 && isepB == -1 ? 9 : (isepB == -1 ? isep1 : isepB)) Sep1 sprintf "%c", isep1 Sep2 sprintf "%c", isep2 ;;CREATE A FUNCTION TABLE iftlen StrayLen Stray, isep1, isep2 if iftlen == 0 then prints "WARNING! StrayNumToFt got empty string as input. Function table with length=1 created, but iftlen=0 returned.\n" iftl = 1 else iftl = iftlen endif ift ftgen iftno, 0, -iftl, -2, 0 ;;INITIALIZE SOME PARAMETERS ilen strlen Stray istartsel = -1; startindex for searched element iel = -1; number of element in Stray and ift iwarleer = 1; is this the start of a new element indx = 0 ;character index inewel = 0 ;new element to find ;;LOOP if ilen == 0 igoto end ;don't go into the loop if Stray is empty loop: Schar strsub Stray, indx, indx+1; this character isep1p strcmp Schar, Sep1; returns 0 if Schar is sep1 isep2p strcmp Schar, Sep2; 0 if Schar is sep2 is_sep = (isep1p == 0 || isep2p == 0 ? 1 : 0) ;1 if Schar is a seperator ;END OF STRING AND NO SEPARATORS BEFORE? if indx == ilen && iwarleer == 0 then Sel strsub Stray, istartsel, -1 inewel = 1 ;FIRST CHARACTER OF AN ELEMENT? elseif is_sep == 0 && iwarleer == 1 then istartsel = indx ;if so, set startindex iwarleer = 0 ;reset info about previous separator iel = iel+1 ;increment element count ;FIRST SEPERATOR AFTER AN ELEMENT? elseif iwarleer == 0 && is_sep == 1 then Sel strsub Stray, istartsel, indx ;get element inewel = 1 ;tell about iwarleer = 1 ;reset info about previous separator endif ;WRITE THE ELEMENT TO THE TABLE if inewel == 1 then inum StrayExpr Sel ;convert expression to number tabw_i inum, iel, ift ;write to ift endif inewel = 0 loop_le indx, 1, ilen, loop end: xout ift, iftlen endop