User-Defined Opcode Database

StrayNumToFt

Converts a string-array which just consists of numbers or simple math expressions to a function table

Download UDO File

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)

Code

  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 

Examples

<CsoundSynthesizer>
<CsOptions>
-n -m0
</CsOptions>
<CsInstruments>

  opcode StrayLen, i, Sjj
;returns the number of elements in Stray. 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
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
  ;returns a number from a binary math expression (without any parentheses)
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
;parses one numerical expression (just one parenthesis allowed) and returns its result
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
;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 like +, -, *, /, ^ and % are allowed, with just one parenthesis in total. 
;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
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 
  
  opcode TbDmpSmpS, 0, iiSo
;prints the content of a table in a simple way, with an additional string as 'introduction'
ifn, iprec, String, ippr xin; function table, float precision while printing, String, parameters per row (maximum = 32)
ippr      =         (ippr == 0 ? 10 : ippr)
iend      =         ftlen(ifn)
indx      =         0
Sformat   sprintf   "%%.%df, ", iprec
Sdump     sprintf   "%s[", String
loop:
ival      tab_i     indx, ifn
Snew      sprintf   Sformat, ival
Sdump     strcat    Sdump, Snew
imod      =         (indx+1) % ippr
 if imod == 0 && indx != iend-1 then
          puts      Sdump, 1
Sdump     =         ""
 endif
          loop_lt   indx, 1, iend, loop
ilen      strlen    Sdump
Slast     strsub    Sdump, 0, ilen-2
		printf_i	"%s]\n", 1, Slast
  endop

instr 1
Stray     strget    p4
          printf_i  "\nStray = '%s'\n", 1, Stray
ipcnt     pcount
if ipcnt == 4 then
ift, ilen StrayNumToFt Stray
elseif ipcnt == 5 then
ift, ilen StrayNumToFt Stray, p5
elseif ipcnt == 6 then
ift, ilen StrayNumToFt Stray, p5, p6
elseif ipcnt == 7 then
ift, ilen StrayNumToFt Stray, p5, p6, p7
endif		
          prints    "ift# = %d, iftlen = %d%n", ift, ilen
          TbDmpSmpS ift, 5, "table content = "
endin 


</CsInstruments>
<CsScore>
i 1 0 .01 "1 -2 3 4 5 6 7"
i . + . "1.2  	2+3.45  6.7/-8.09 "
i . + . "  	15%12  -5-3   "
i . + . "	 2^0.6	 2^(1/12) 2^(-1/12)  	16 32"
i . + . "123*-4.56	 "
i . + . "123*(-4.56)	 "
i . + . "	 "
i . + . ""
i . + . "1+2.7 2^(1/12) 3.10*65 27%5"
i . + . "1+2.7 2^(1/12) 3.10*65 27%6" 13 ;write table number 13
i . + . "1+2.7,2^(1/12),3.10*65,27%7" 0 44 ;just commas are seperators
i . + . "1+2.7, 2^(1/12), 3.10*65, 27%8" 0 44 ;no problem to write spaces though
i . + . "1+2.7,2^(1/12)|3.10*65,27%9" 0 44 124 ;commas and '|' are seperators
e
</CsScore>
</CsoundSynthesizer>

Credits

joachim heintz april 2010 / sept 2011 / feb 2012


Previous Home Next
StrayNumLen   PitchShifter