Error processing request

Parameters

CONTENT_LENGTH0
REQUEST_METHODGET
REQUEST_URI/revision/Building+kiss%5Ffft+library+extension+for+TCL?V=17
QUERY_STRINGV=17
CONTENT_TYPE
DOCUMENT_URI/revision/Building+kiss_fft+library+extension+for+TCL
DOCUMENT_ROOT/var/www/nikit/nikit/nginx/../docroot
SCGI1
SERVER_PROTOCOLHTTP/1.1
HTTPSon
REMOTE_ADDR172.70.127.58
REMOTE_PORT30220
SERVER_PORT4443
SERVER_NAMEwiki.tcl-lang.org
HTTP_HOSTwiki.tcl-lang.org
HTTP_CONNECTIONKeep-Alive
HTTP_ACCEPT_ENCODINGgzip, br
HTTP_X_FORWARDED_FOR18.221.187.121
HTTP_CF_RAY879e108bccc513cf-ORD
HTTP_X_FORWARDED_PROTOhttps
HTTP_CF_VISITOR{"scheme":"https"}
HTTP_ACCEPT*/*
HTTP_USER_AGENTMozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; [email protected])
HTTP_CF_CONNECTING_IP18.221.187.121
HTTP_CDN_LOOPcloudflare
HTTP_CF_IPCOUNTRYUS

Body


Error

Unknow state transition: LINE -> END

-code

1

-level

0

-errorstack

INNER {returnImm {Unknow state transition: LINE -> END} {}} CALL {my render_wikit {Building kiss_fft library extension for TCL} To\ create\ a\ C\ extension\ loadable\ by\ tclsh\ is\ quite\ easy.\ However,\ direction\ for\ doing\ it\ is\ well\ hidden\ in\ various\ books\ especially\ passing\ C\ array\ of\ struct\ which\ is\ commonly\ required\ by\ engineering\ application.\ As\ an\ example,\ I'll\ show\ here\ how\ to\ wrap\ the\ kiss_fft\ library\ for\ tclsh\ interpreter\ using\ Tcl\ C\ API\ calls.\ I've\ also\ tried\ to\ use\ SWIG,\ and\ it\ seems\ to\ be\ next\ to\ impossible\ to\ use\ it\ to\ pass\ array\ of\ C\ struct.\ Anyone\ with\ knowledge\ of\ how\ to\ do\ this\ using\ SWIG,\ please\ share\ it\ here,\ Thanks!\ \nThe\ basic\ idea\ is\ to\ represent\ C\ struct\ as\ Tcl\ list\ and\ then\ use\ various\ Tcl\ C\ API\ to\ convert\ Tcl_Obj\ to\ native\ C\ data\ types.\ call\ the\ kiss_fft\ then\ convert\ the\ output\ array\ of\ struct\ back\ to\ Tcl\ list\ before\ passing\ it\ back\ to\ Tcl\ interpreter.\n\nKiss_fft\ is\ an\ open\ source\ library\ for\ doing\ mix-radix\ Fast\ Fourier\ Transform.\ it\ can\ be\ downloaded\ from\ its\ homepage\ at:\ http://sourceforge.net/projects/kissfft\n\nI've\ created\ two\ C\ extension\ Tcl\ commands,\ kiss_fft\ for\ complex\ data\ input\ and\ kiss_fftr\ for\ real\ data\ input\ in\ this\ post\;\ the\ rest\ of\ the\ library\ can\ be\ easily\ made\ available\ as\ Tcl\ commands.\n\nI\ hope\ by\ seeing\ an\ example\ of\ how\ to\ create\ Tcl\ extension\ command\ using\ C\ APIs\ will\ help\ those\ of\ us\ who\ have\ no\ idea\ how\ to\ start\ solving\ problem\ like\ this.\nAs\ you\ can\ see,\ the\ required\ C\ code\ is\ quite\ short\ and\ rather\ simple\ to\ extend\ the\ Tcl\ if\ shown\ by\ some\ example.\ Happy\ coding!\n\n\ \n\n\n======\n//\ written\ by\ Long\ To,\ 10/24/2015\ to\ interface\ with\ TCL.\ note:\ inverse\ FFT\ needs\ to\ be\ scaled\ down\ by\ FFT\ length\n\n#include\ \"kiss_fft.h\"\n#include\ <tcl.h>\n\n//\ following\ declaration\ is\ needed\ in\ Windows\ using\ MSVC\ compiler\ for\ the\ package\ to\ detect\ the\ ???_Init()\ function\n\n__declspec(dllexport)\ int\ Kiss_fft_Init(Tcl_Interp\ *)\;\n\nint\ Kiss_fftCmd(ClientData\ clientData,\ Tcl_Interp\ *interp,\ int\ objc,\ Tcl_Obj\ *CONST\ objv\[\])\;\nint\ Kiss_fftrCmd(ClientData\ clientData,\ Tcl_Interp\ *interp,\ int\ objc,\ Tcl_Obj\ *CONST\ objv\[\])\;\n\nint\ Kiss_fft_Init(Tcl_Interp\ *interp)\ \{\n\ \ \ \ \ \ \ \ if(Tcl_InitStubs(interp,\ TCL_VERSION,\ 0)\ ==\ NULL)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (Tcl_PkgProvide(interp,\ \"Kiss_fft\",\ \"1.1\")\ ==\ TCL_ERROR)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ Tcl_CreateObjCommand(interp,\ \"kiss_fft\",\ Kiss_fftCmd,\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (ClientData)NULL,\ (Tcl_CmdDeleteProc\ *)NULL)\;\n\ \ \ \ \ \ \ \ Tcl_CreateObjCommand(interp,\ \"kiss_fftr\",\ Kiss_fftrCmd,\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (ClientData)NULL,\ (Tcl_CmdDeleteProc\ *)NULL)\;\n\ \ \ \ \ \ \ \ return\ TCL_OK\;\n\}\n\nint\ Kiss_fftCmd(ClientData\ clientData,\ Tcl_Interp\ *interp,\ int\ objc,\ Tcl_Obj\ *CONST\ objv\[\])\ \{\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ if\ (objc\ !=\ 3)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_WrongNumArgs(interp,\ objc,\ objv,\ \"\ ?inverse?\ ?fin?\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ int\ count,\ inverse\;\n\ \ \ \ \ \ \ \ Tcl_Obj\ *list_in\ =\ objv\[2\]\;\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ //\ extract\ the\ 1st\ arg\ of\ the\ kiss_fft\ command\ as\ an\ integer:\ 0\ for\ foward\ transform,\ 1\ for\ inverse\ transform\n\ \ \ \ \ \ \ \ if\ (Tcl_GetIntFromObj(interp,\ objv\[1\],\ &inverse)\ !=\ TCL_OK)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Couldn't\ get\ direction\ of\ transform\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (Tcl_ListObjLength(interp,\ list_in,\ &count)\ !=\ TCL_OK)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Couldn't\ get\ fin\ length\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ int\ nfft\ =\ count\;\n\n\ \ \ \ \ \ \ \ kiss_fft_cpx\ *fin\ =\ (kiss_fft_cpx\ *)malloc(sizeof(kiss_fft_cpx)\ *\ nfft)\;\n\ \ \ \ \ \ \ \ kiss_fft_cpx\ *fout\ =\ (kiss_fft_cpx\ *)malloc(sizeof(kiss_fft_cpx)\ *\ nfft)\;\n\ \ \ \ \ \ \ \ Tcl_Obj\ *real\;\ \ //\ individual\ element\ of\ Tcl_Obj\ double\ represent\ the\ real\ part\ of\ the\ complex\ number\n\ \ \ \ \ \ \ \ Tcl_Obj\ *imag\;\ \ //\ individual\ element\ of\ Tcl_Obj\ double\ represent\ the\ imaginary\ part\ of\ the\ complex\ number\n\ \ \ \ \ \ \ \ Tcl_Obj\ *L\;\ \ //\ inner\ sublist\ of\ outer\ list\ list_in\n\n\ \ \ \ \ \ \ \ for\ (size_t\ i=0\;\ i<count\;\ ++i)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (Tcl_ListObjIndex(interp,\ list_in,\ i,\ &L)\ !=\ TCL_OK)\ \{\ \ \ //\ outer\ list\ list_in\ passed\ in\ from\ TCL\ command\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Invalid\ index\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (Tcl_ListObjIndex(interp,\ L,\ 0,\ &real)\ !=\ TCL_OK)\ \{\ \ //\ real\ part\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Invalid\ index\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (Tcl_ListObjIndex(interp,\ L,\ 1,\ &imag)\ !=\ TCL_OK)\ \{\ \ //\ imaginary\ part\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Invalid\ index\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (Tcl_GetDoubleFromObj(interp,\ real,\ &fin\[i\].r)\ !=\ TCL_OK)\ \{\ \ //\ convert\ Tcl_Obj\ to\ double\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Not\ a\ double\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (Tcl_GetDoubleFromObj(interp,\ imag,\ &fin\[i\].i)\ !=\ TCL_OK)\ \{\ \ //\ convert\ Tcl_Obj\ to\ double\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Not\ a\ double\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ kiss_fft_cfg\ cfg\ =\ kiss_fft_alloc(nfft,inverse,0,0)\;\n\ \ \ \ \ \ \ \ kiss_fft(cfg,fin,fout)\;\n\n\ \ \ \ \ \ \ \ free(cfg)\;\n\n\ \ \ \ \ \ \ \ Tcl_Obj\ *list\ =\ Tcl_NewListObj(0,\ NULL)\;\n\ \ \ \ \ \ \ \ Tcl_Obj*\ Re\;\n\ \ \ \ \ \ \ \ Tcl_Obj*\ Im\;\n\ \ \ \ \ \ \ \ Tcl_Obj*\ C\;\n\ \ \ \ \ \ \ \ for\ (\ size_t\ i=0\;\ i<nfft\;\ ++i\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Re\ =\ Tcl_NewDoubleObj(fout\[i\].r)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Im\ =\ Tcl_NewDoubleObj(fout\[i\].i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ C\ =\ Tcl_NewListObj(0,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (\ Tcl_ListObjAppendElement(interp,\ C,\ Re)\ !=\ TCL_OK\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Couldn't\ append\ real\ part\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (\ Tcl_ListObjAppendElement(interp,\ C,\ Im)\ !=\ TCL_OK\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Couldn't\ append\ imaginary\ part\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (\ Tcl_ListObjAppendElement(interp,\ list,\ C)\ !=\ TCL_OK\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Couldn't\ append\ complex\ result\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ free(fin)\;\n\ \ \ \ \ \ \ \ free(fout)\;\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ Tcl_SetObjResult(interp,\ list)\;\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ return\ TCL_OK\;\n\}\n\nint\ Kiss_fftrCmd(ClientData\ clientData,\ Tcl_Interp\ *interp,\ int\ objc,\ Tcl_Obj\ *CONST\ objv\[\])\ \{\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ if\ (objc\ !=\ 3)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_WrongNumArgs(interp,\ objc,\ objv,\ \"\ ?inverse?\ ?fin?\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ int\ count,\ inverse\;\n\ \ \ \ \ \ \ \ Tcl_Obj\ *list_in\ =\ objv\[2\]\;\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ //\ extract\ the\ 1st\ arg\ of\ the\ kiss_fft\ command\ as\ an\ integer:\ 0\ for\ foward\ transform,\ 1\ for\ inverse\ transform\n\ \ \ \ \ \ \ \ if\ (Tcl_GetIntFromObj(interp,\ objv\[1\],\ &inverse)\ !=\ TCL_OK)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Couldn't\ get\ direction\ of\ transform\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (Tcl_ListObjLength(interp,\ list_in,\ &count)\ !=\ TCL_OK)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Couldn't\ get\ fin\ length\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ int\ nfft\ =\ count\;\n\n\ \ \ \ \ \ \ \ kiss_fft_cpx\ *fin\ =\ (kiss_fft_cpx\ *)malloc(sizeof(kiss_fft_cpx)\ *\ nfft)\;\n\ \ \ \ \ \ \ \ kiss_fft_cpx\ *fout\ =\ (kiss_fft_cpx\ *)malloc(sizeof(kiss_fft_cpx)\ *\ nfft)\;\n\ \ \ \ \ \ \ \ Tcl_Obj\ *x\;\ \ //\ individual\ element\ of\ double\n\ \ \ \ \ \ \ \ for\ (size_t\ i=0\;\ i<nfft\;\ ++i)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (Tcl_ListObjIndex(interp,\ list_in,\ i,\ &x)\ !=\ TCL_OK)\ \{\ \ \ //\ list_in\ passed\ in\ from\ TCL\ command\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Invalid\ index\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (Tcl_GetDoubleFromObj(interp,\ x,\ &fin\[i\].r)\ !=\ TCL_OK)\ \{\ \ //\ individual\ list\ element\ of\ the\ list_in\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Not\ a\ double\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fin\[i\].i\ =\ 0.0\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ kiss_fft_cfg\ cfg\ =\ kiss_fft_alloc(nfft,inverse,0,0)\;\n\n\ \ \ \ \ \ \ \ kiss_fft(cfg,fin,fout)\;\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ free(cfg)\;\n\n\ \ \ \ \ \ \ \ Tcl_Obj\ *list\ =\ Tcl_NewListObj(0,\ NULL)\;\n\ \ \ \ \ \ \ \ Tcl_Obj*\ Re\;\n\ \ \ \ \ \ \ \ Tcl_Obj*\ Im\;\n\ \ \ \ \ \ \ \ Tcl_Obj*\ C\;\n\ \ \ \ \ \ \ \ for\ (\ size_t\ i=0\;\ i<nfft\;\ ++i\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Re\ =\ Tcl_NewDoubleObj(fout\[i\].r)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Im\ =\ Tcl_NewDoubleObj(fout\[i\].i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ C\ =\ Tcl_NewListObj(0,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (\ Tcl_ListObjAppendElement(interp,\ C,\ Re)\ !=\ TCL_OK\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Couldn't\ append\ real\ part\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (\ Tcl_ListObjAppendElement(interp,\ C,\ Im)\ !=\ TCL_OK\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Couldn't\ append\ imaginary\ part\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (\ Tcl_ListObjAppendElement(interp,\ list,\ C)\ !=\ TCL_OK\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Couldn't\ append\ complex\ result\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ free(fin)\;\n\ \ \ \ \ \ \ \ free(fout)\;\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ Tcl_SetObjResult(interp,\ list)\;\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ return\ TCL_OK\;\n\}\n======\n\nTo\ compile\ the\ code\ using\ Visual\ C++:\n\n======\ncl\ -c\ kiss_fft.c\ /Ox\ncl\ -c\ tclkiss_fft.c\ \ /Ox\ /DUSE_TCL_STUBS\ /Ic:\\tcl\\include\nlink\ /DLL\ /LTCG\ /out:kiss_fft.dll\ kiss_fft.obj\ tclkiss_fft.obj\ /libpath:c:\\tcl\\lib\ tclstub86.lib\n======\n\nfollowing\ is\ a\ test\ Tcl\ script\ (runme.tcl)\ to\ verify\ everything\ is\ working:\n\n======\ncatch\ \{\ load\ ./kiss_fft\[info\ sharedlibextension\]\ kiss_fft\}\n\nset\ cin\ \{\{1\ 0\}\\\n\ \ \ \ \ \ \ \ \{2\ 0\}\\\n\ \ \ \ \ \ \ \ \{3\ 0\}\\\n\ \ \ \ \ \ \ \ \{4\ 0\}\\\n\ \ \ \ \ \ \ \ \{5\ 0\}\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \nputs\ \"length\ of\ list\ cin\ is:\ \[llength\ \$cin\]\"\n\nputs\ \$cin\nputs\ \"\\n\"\nset\ inverse\ 0\nputs\ \"set\ inverse\ to:\ \$inverse\"\nputs\ \"to\ perform\ foward\ FFT\ on\ a\ complex\ series:\ \$cin\"\nset\ F\ \[kiss_fft\ \$inverse\ \$cin\]\ \nputs\ \"\\noutput\ is:\"\n\nforeach\ el\ \$F\ \{\n\ \ \ \ \ \ \ \ puts\ \\\{\$el\\\}\n\}\n\nputs\ \"\\n\"\n\nset\ inverse\ 1\nputs\ \"set\ inverse\ to:\ \$inverse\"\nputs\ \"to\ perform\ inverse\ FFT\ on\ a\ complex\ series:\ \$F\"\nset\ I\ \[kiss_fft\ \$inverse\ \$F\]\nputs\ \"\\noutput\ is:\"\nforeach\ el\ \$I\ \{\n\ \ \ \ \ \ \ \ puts\ \\\{\$el\\\}\n\}\nputs\ \"note:\ the\ output\ of\ inverse\ FFT\ needs\ be\ scaled\ by\ 1/\[llength\ \$I\]\"\n\nif\ \{0\}\ \{\nforeach\ l\ \$I\ \{\n\ \ \ \ \ \ \ \ foreach\ inner\ \$l\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ inner\ \[expr\ \$inner/\[llength\ \$I\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ \$inner\n\ \ \ \ \ \ \ \ \}\n\}\n\}\n\nunset\ I\nunset\ F\nunset\ cin\n\nputs\ \"\\n\"\n\nset\ R\ \{1\ 2\ 3\ 4\}\nputs\ \"perform\ FFT\ transform\ of\ real\ series:\ \$R\"\nset\ inverse\ 0\nputs\ \"inverse\ is:\ \$inverse\"\nset\ O\ \[kiss_fftr\ \$inverse\ \$R\]\nputs\ \"output\ is:\ \$O\"\n\n\n======\n\nThe\ output\ from\ the\ script:\n\n======\nC:\\tcl>tclsh86t\ runme.tcl\nlength\ of\ list\ cin\ is:\ 5\n\{1\ 0\}\ \{2\ 0\}\ \{3\ 0\}\ \{4\ 0\}\ \{5\ 0\}\n\n\nset\ inverse\ to:\ 0\nto\ perform\ foward\ FFT\ on\ a\ complex\ series:\ \{1\ 0\}\ \{2\ 0\}\ \{3\ 0\}\ \{4\ 0\}\ \{5\ 0\}\n\noutput\ is:\n\{15.0\ 0.0\}\n\{-2.499999999999999\ 3.440954801177934\}\n\{-2.499999999999999\ 0.8122992405822661\}\n\{-2.499999999999999\ -0.8122992405822661\}\n\{-2.499999999999999\ -3.440954801177934\}\n\n\nset\ inverse\ to:\ 1\nto\ perform\ inverse\ FFT\ on\ a\ complex\ series:\ \{15.0\ 0.0\}\ \{-2.499999999999999\ 3.440954801177934\}\ \{-2.499999999999999\ 0.8122992405822661\}\ \{-2.499999999999999\ -0.8122992405822661\}\ \{-2.499999999999999\ -3.440954801177934\}\n\noutput\ is:\n\{5.0000000000000036\ 0.0\}\n\{10.0\ 0.0\}\n\{15.0\ 0.0\}\n\{20.0\ 0.0\}\n\{25.0\ 0.0\}\nnote:\ the\ output\ of\ inverse\ FFT\ needs\ be\ scaled\ by\ 1/5\n\n\nperform\ FFT\ transform\ of\ real\ series:\ 1\ 2\ 3\ 4\ninverse\ is:\ 0\noutput\ is:\ \{10.0\ 0.0\}\ \{-2.0\ 2.0\}\ \{-2.0\ 0.0\}\ \{-2.0\ -2.0\}\nC:\\tcl>\n\n\n<<categories>>\ Engineering\ |\ FFT\ |\ Fourier\ Transform regexp2} CALL {my render {Building kiss_fft library extension for TCL} To\ create\ a\ C\ extension\ loadable\ by\ tclsh\ is\ quite\ easy.\ However,\ direction\ for\ doing\ it\ is\ well\ hidden\ in\ various\ books\ especially\ passing\ C\ array\ of\ struct\ which\ is\ commonly\ required\ by\ engineering\ application.\ As\ an\ example,\ I'll\ show\ here\ how\ to\ wrap\ the\ kiss_fft\ library\ for\ tclsh\ interpreter\ using\ Tcl\ C\ API\ calls.\ I've\ also\ tried\ to\ use\ SWIG,\ and\ it\ seems\ to\ be\ next\ to\ impossible\ to\ use\ it\ to\ pass\ array\ of\ C\ struct.\ Anyone\ with\ knowledge\ of\ how\ to\ do\ this\ using\ SWIG,\ please\ share\ it\ here,\ Thanks!\ \nThe\ basic\ idea\ is\ to\ represent\ C\ struct\ as\ Tcl\ list\ and\ then\ use\ various\ Tcl\ C\ API\ to\ convert\ Tcl_Obj\ to\ native\ C\ data\ types.\ call\ the\ kiss_fft\ then\ convert\ the\ output\ array\ of\ struct\ back\ to\ Tcl\ list\ before\ passing\ it\ back\ to\ Tcl\ interpreter.\n\nKiss_fft\ is\ an\ open\ source\ library\ for\ doing\ mix-radix\ Fast\ Fourier\ Transform.\ it\ can\ be\ downloaded\ from\ its\ homepage\ at:\ http://sourceforge.net/projects/kissfft\n\nI've\ created\ two\ C\ extension\ Tcl\ commands,\ kiss_fft\ for\ complex\ data\ input\ and\ kiss_fftr\ for\ real\ data\ input\ in\ this\ post\;\ the\ rest\ of\ the\ library\ can\ be\ easily\ made\ available\ as\ Tcl\ commands.\n\nI\ hope\ by\ seeing\ an\ example\ of\ how\ to\ create\ Tcl\ extension\ command\ using\ C\ APIs\ will\ help\ those\ of\ us\ who\ have\ no\ idea\ how\ to\ start\ solving\ problem\ like\ this.\nAs\ you\ can\ see,\ the\ required\ C\ code\ is\ quite\ short\ and\ rather\ simple\ to\ extend\ the\ Tcl\ if\ shown\ by\ some\ example.\ Happy\ coding!\n\n\ \n\n\n======\n//\ written\ by\ Long\ To,\ 10/24/2015\ to\ interface\ with\ TCL.\ note:\ inverse\ FFT\ needs\ to\ be\ scaled\ down\ by\ FFT\ length\n\n#include\ \"kiss_fft.h\"\n#include\ <tcl.h>\n\n//\ following\ declaration\ is\ needed\ in\ Windows\ using\ MSVC\ compiler\ for\ the\ package\ to\ detect\ the\ ???_Init()\ function\n\n__declspec(dllexport)\ int\ Kiss_fft_Init(Tcl_Interp\ *)\;\n\nint\ Kiss_fftCmd(ClientData\ clientData,\ Tcl_Interp\ *interp,\ int\ objc,\ Tcl_Obj\ *CONST\ objv\[\])\;\nint\ Kiss_fftrCmd(ClientData\ clientData,\ Tcl_Interp\ *interp,\ int\ objc,\ Tcl_Obj\ *CONST\ objv\[\])\;\n\nint\ Kiss_fft_Init(Tcl_Interp\ *interp)\ \{\n\ \ \ \ \ \ \ \ if(Tcl_InitStubs(interp,\ TCL_VERSION,\ 0)\ ==\ NULL)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (Tcl_PkgProvide(interp,\ \"Kiss_fft\",\ \"1.1\")\ ==\ TCL_ERROR)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ Tcl_CreateObjCommand(interp,\ \"kiss_fft\",\ Kiss_fftCmd,\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (ClientData)NULL,\ (Tcl_CmdDeleteProc\ *)NULL)\;\n\ \ \ \ \ \ \ \ Tcl_CreateObjCommand(interp,\ \"kiss_fftr\",\ Kiss_fftrCmd,\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (ClientData)NULL,\ (Tcl_CmdDeleteProc\ *)NULL)\;\n\ \ \ \ \ \ \ \ return\ TCL_OK\;\n\}\n\nint\ Kiss_fftCmd(ClientData\ clientData,\ Tcl_Interp\ *interp,\ int\ objc,\ Tcl_Obj\ *CONST\ objv\[\])\ \{\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ if\ (objc\ !=\ 3)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_WrongNumArgs(interp,\ objc,\ objv,\ \"\ ?inverse?\ ?fin?\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ int\ count,\ inverse\;\n\ \ \ \ \ \ \ \ Tcl_Obj\ *list_in\ =\ objv\[2\]\;\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ //\ extract\ the\ 1st\ arg\ of\ the\ kiss_fft\ command\ as\ an\ integer:\ 0\ for\ foward\ transform,\ 1\ for\ inverse\ transform\n\ \ \ \ \ \ \ \ if\ (Tcl_GetIntFromObj(interp,\ objv\[1\],\ &inverse)\ !=\ TCL_OK)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Couldn't\ get\ direction\ of\ transform\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (Tcl_ListObjLength(interp,\ list_in,\ &count)\ !=\ TCL_OK)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Couldn't\ get\ fin\ length\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ int\ nfft\ =\ count\;\n\n\ \ \ \ \ \ \ \ kiss_fft_cpx\ *fin\ =\ (kiss_fft_cpx\ *)malloc(sizeof(kiss_fft_cpx)\ *\ nfft)\;\n\ \ \ \ \ \ \ \ kiss_fft_cpx\ *fout\ =\ (kiss_fft_cpx\ *)malloc(sizeof(kiss_fft_cpx)\ *\ nfft)\;\n\ \ \ \ \ \ \ \ Tcl_Obj\ *real\;\ \ //\ individual\ element\ of\ Tcl_Obj\ double\ represent\ the\ real\ part\ of\ the\ complex\ number\n\ \ \ \ \ \ \ \ Tcl_Obj\ *imag\;\ \ //\ individual\ element\ of\ Tcl_Obj\ double\ represent\ the\ imaginary\ part\ of\ the\ complex\ number\n\ \ \ \ \ \ \ \ Tcl_Obj\ *L\;\ \ //\ inner\ sublist\ of\ outer\ list\ list_in\n\n\ \ \ \ \ \ \ \ for\ (size_t\ i=0\;\ i<count\;\ ++i)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (Tcl_ListObjIndex(interp,\ list_in,\ i,\ &L)\ !=\ TCL_OK)\ \{\ \ \ //\ outer\ list\ list_in\ passed\ in\ from\ TCL\ command\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Invalid\ index\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (Tcl_ListObjIndex(interp,\ L,\ 0,\ &real)\ !=\ TCL_OK)\ \{\ \ //\ real\ part\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Invalid\ index\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (Tcl_ListObjIndex(interp,\ L,\ 1,\ &imag)\ !=\ TCL_OK)\ \{\ \ //\ imaginary\ part\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Invalid\ index\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (Tcl_GetDoubleFromObj(interp,\ real,\ &fin\[i\].r)\ !=\ TCL_OK)\ \{\ \ //\ convert\ Tcl_Obj\ to\ double\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Not\ a\ double\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (Tcl_GetDoubleFromObj(interp,\ imag,\ &fin\[i\].i)\ !=\ TCL_OK)\ \{\ \ //\ convert\ Tcl_Obj\ to\ double\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Not\ a\ double\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ kiss_fft_cfg\ cfg\ =\ kiss_fft_alloc(nfft,inverse,0,0)\;\n\ \ \ \ \ \ \ \ kiss_fft(cfg,fin,fout)\;\n\n\ \ \ \ \ \ \ \ free(cfg)\;\n\n\ \ \ \ \ \ \ \ Tcl_Obj\ *list\ =\ Tcl_NewListObj(0,\ NULL)\;\n\ \ \ \ \ \ \ \ Tcl_Obj*\ Re\;\n\ \ \ \ \ \ \ \ Tcl_Obj*\ Im\;\n\ \ \ \ \ \ \ \ Tcl_Obj*\ C\;\n\ \ \ \ \ \ \ \ for\ (\ size_t\ i=0\;\ i<nfft\;\ ++i\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Re\ =\ Tcl_NewDoubleObj(fout\[i\].r)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Im\ =\ Tcl_NewDoubleObj(fout\[i\].i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ C\ =\ Tcl_NewListObj(0,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (\ Tcl_ListObjAppendElement(interp,\ C,\ Re)\ !=\ TCL_OK\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Couldn't\ append\ real\ part\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (\ Tcl_ListObjAppendElement(interp,\ C,\ Im)\ !=\ TCL_OK\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Couldn't\ append\ imaginary\ part\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (\ Tcl_ListObjAppendElement(interp,\ list,\ C)\ !=\ TCL_OK\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Couldn't\ append\ complex\ result\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ free(fin)\;\n\ \ \ \ \ \ \ \ free(fout)\;\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ Tcl_SetObjResult(interp,\ list)\;\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ return\ TCL_OK\;\n\}\n\nint\ Kiss_fftrCmd(ClientData\ clientData,\ Tcl_Interp\ *interp,\ int\ objc,\ Tcl_Obj\ *CONST\ objv\[\])\ \{\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ if\ (objc\ !=\ 3)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_WrongNumArgs(interp,\ objc,\ objv,\ \"\ ?inverse?\ ?fin?\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ int\ count,\ inverse\;\n\ \ \ \ \ \ \ \ Tcl_Obj\ *list_in\ =\ objv\[2\]\;\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ //\ extract\ the\ 1st\ arg\ of\ the\ kiss_fft\ command\ as\ an\ integer:\ 0\ for\ foward\ transform,\ 1\ for\ inverse\ transform\n\ \ \ \ \ \ \ \ if\ (Tcl_GetIntFromObj(interp,\ objv\[1\],\ &inverse)\ !=\ TCL_OK)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Couldn't\ get\ direction\ of\ transform\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (Tcl_ListObjLength(interp,\ list_in,\ &count)\ !=\ TCL_OK)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Couldn't\ get\ fin\ length\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ int\ nfft\ =\ count\;\n\n\ \ \ \ \ \ \ \ kiss_fft_cpx\ *fin\ =\ (kiss_fft_cpx\ *)malloc(sizeof(kiss_fft_cpx)\ *\ nfft)\;\n\ \ \ \ \ \ \ \ kiss_fft_cpx\ *fout\ =\ (kiss_fft_cpx\ *)malloc(sizeof(kiss_fft_cpx)\ *\ nfft)\;\n\ \ \ \ \ \ \ \ Tcl_Obj\ *x\;\ \ //\ individual\ element\ of\ double\n\ \ \ \ \ \ \ \ for\ (size_t\ i=0\;\ i<nfft\;\ ++i)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (Tcl_ListObjIndex(interp,\ list_in,\ i,\ &x)\ !=\ TCL_OK)\ \{\ \ \ //\ list_in\ passed\ in\ from\ TCL\ command\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Invalid\ index\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (Tcl_GetDoubleFromObj(interp,\ x,\ &fin\[i\].r)\ !=\ TCL_OK)\ \{\ \ //\ individual\ list\ element\ of\ the\ list_in\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Not\ a\ double\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fin\[i\].i\ =\ 0.0\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ kiss_fft_cfg\ cfg\ =\ kiss_fft_alloc(nfft,inverse,0,0)\;\n\n\ \ \ \ \ \ \ \ kiss_fft(cfg,fin,fout)\;\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ free(cfg)\;\n\n\ \ \ \ \ \ \ \ Tcl_Obj\ *list\ =\ Tcl_NewListObj(0,\ NULL)\;\n\ \ \ \ \ \ \ \ Tcl_Obj*\ Re\;\n\ \ \ \ \ \ \ \ Tcl_Obj*\ Im\;\n\ \ \ \ \ \ \ \ Tcl_Obj*\ C\;\n\ \ \ \ \ \ \ \ for\ (\ size_t\ i=0\;\ i<nfft\;\ ++i\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Re\ =\ Tcl_NewDoubleObj(fout\[i\].r)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Im\ =\ Tcl_NewDoubleObj(fout\[i\].i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ C\ =\ Tcl_NewListObj(0,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (\ Tcl_ListObjAppendElement(interp,\ C,\ Re)\ !=\ TCL_OK\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Couldn't\ append\ real\ part\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (\ Tcl_ListObjAppendElement(interp,\ C,\ Im)\ !=\ TCL_OK\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Couldn't\ append\ imaginary\ part\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (\ Tcl_ListObjAppendElement(interp,\ list,\ C)\ !=\ TCL_OK\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Tcl_AppendResult(interp,\ \"\ Couldn't\ append\ complex\ result\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ TCL_ERROR\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ free(fin)\;\n\ \ \ \ \ \ \ \ free(fout)\;\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ Tcl_SetObjResult(interp,\ list)\;\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ return\ TCL_OK\;\n\}\n======\n\nTo\ compile\ the\ code\ using\ Visual\ C++:\n\n======\ncl\ -c\ kiss_fft.c\ /Ox\ncl\ -c\ tclkiss_fft.c\ \ /Ox\ /DUSE_TCL_STUBS\ /Ic:\\tcl\\include\nlink\ /DLL\ /LTCG\ /out:kiss_fft.dll\ kiss_fft.obj\ tclkiss_fft.obj\ /libpath:c:\\tcl\\lib\ tclstub86.lib\n======\n\nfollowing\ is\ a\ test\ Tcl\ script\ (runme.tcl)\ to\ verify\ everything\ is\ working:\n\n======\ncatch\ \{\ load\ ./kiss_fft\[info\ sharedlibextension\]\ kiss_fft\}\n\nset\ cin\ \{\{1\ 0\}\\\n\ \ \ \ \ \ \ \ \{2\ 0\}\\\n\ \ \ \ \ \ \ \ \{3\ 0\}\\\n\ \ \ \ \ \ \ \ \{4\ 0\}\\\n\ \ \ \ \ \ \ \ \{5\ 0\}\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \nputs\ \"length\ of\ list\ cin\ is:\ \[llength\ \$cin\]\"\n\nputs\ \$cin\nputs\ \"\\n\"\nset\ inverse\ 0\nputs\ \"set\ inverse\ to:\ \$inverse\"\nputs\ \"to\ perform\ foward\ FFT\ on\ a\ complex\ series:\ \$cin\"\nset\ F\ \[kiss_fft\ \$inverse\ \$cin\]\ \nputs\ \"\\noutput\ is:\"\n\nforeach\ el\ \$F\ \{\n\ \ \ \ \ \ \ \ puts\ \\\{\$el\\\}\n\}\n\nputs\ \"\\n\"\n\nset\ inverse\ 1\nputs\ \"set\ inverse\ to:\ \$inverse\"\nputs\ \"to\ perform\ inverse\ FFT\ on\ a\ complex\ series:\ \$F\"\nset\ I\ \[kiss_fft\ \$inverse\ \$F\]\nputs\ \"\\noutput\ is:\"\nforeach\ el\ \$I\ \{\n\ \ \ \ \ \ \ \ puts\ \\\{\$el\\\}\n\}\nputs\ \"note:\ the\ output\ of\ inverse\ FFT\ needs\ be\ scaled\ by\ 1/\[llength\ \$I\]\"\n\nif\ \{0\}\ \{\nforeach\ l\ \$I\ \{\n\ \ \ \ \ \ \ \ foreach\ inner\ \$l\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ inner\ \[expr\ \$inner/\[llength\ \$I\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ \$inner\n\ \ \ \ \ \ \ \ \}\n\}\n\}\n\nunset\ I\nunset\ F\nunset\ cin\n\nputs\ \"\\n\"\n\nset\ R\ \{1\ 2\ 3\ 4\}\nputs\ \"perform\ FFT\ transform\ of\ real\ series:\ \$R\"\nset\ inverse\ 0\nputs\ \"inverse\ is:\ \$inverse\"\nset\ O\ \[kiss_fftr\ \$inverse\ \$R\]\nputs\ \"output\ is:\ \$O\"\n\n\n======\n\nThe\ output\ from\ the\ script:\n\n======\nC:\\tcl>tclsh86t\ runme.tcl\nlength\ of\ list\ cin\ is:\ 5\n\{1\ 0\}\ \{2\ 0\}\ \{3\ 0\}\ \{4\ 0\}\ \{5\ 0\}\n\n\nset\ inverse\ to:\ 0\nto\ perform\ foward\ FFT\ on\ a\ complex\ series:\ \{1\ 0\}\ \{2\ 0\}\ \{3\ 0\}\ \{4\ 0\}\ \{5\ 0\}\n\noutput\ is:\n\{15.0\ 0.0\}\n\{-2.499999999999999\ 3.440954801177934\}\n\{-2.499999999999999\ 0.8122992405822661\}\n\{-2.499999999999999\ -0.8122992405822661\}\n\{-2.499999999999999\ -3.440954801177934\}\n\n\nset\ inverse\ to:\ 1\nto\ perform\ inverse\ FFT\ on\ a\ complex\ series:\ \{15.0\ 0.0\}\ \{-2.499999999999999\ 3.440954801177934\}\ \{-2.499999999999999\ 0.8122992405822661\}\ \{-2.499999999999999\ -0.8122992405822661\}\ \{-2.499999999999999\ -3.440954801177934\}\n\noutput\ is:\n\{5.0000000000000036\ 0.0\}\n\{10.0\ 0.0\}\n\{15.0\ 0.0\}\n\{20.0\ 0.0\}\n\{25.0\ 0.0\}\nnote:\ the\ output\ of\ inverse\ FFT\ needs\ be\ scaled\ by\ 1/5\n\n\nperform\ FFT\ transform\ of\ real\ series:\ 1\ 2\ 3\ 4\ninverse\ is:\ 0\noutput\ is:\ \{10.0\ 0.0\}\ \{-2.0\ 2.0\}\ \{-2.0\ 0.0\}\ \{-2.0\ -2.0\}\nC:\\tcl>\n\n\n<<categories>>\ Engineering\ |\ FFT\ |\ Fourier\ Transform} CALL {my revision {Building kiss_fft library extension for TCL}} CALL {::oo::Obj830170 process revision/Building+kiss%5Ffft+library+extension+for+TCL} CALL {::oo::Obj830168 process}

-errorcode

NONE

-errorinfo

Unknow state transition: LINE -> END
    while executing
"error $msg"
    (class "::Wiki" method "render_wikit" line 6)
    invoked from within
"my render_$default_markup $N $C $mkup_rendering_engine"
    (class "::Wiki" method "render" line 8)
    invoked from within
"my render $name $C"
    (class "::Wiki" method "revision" line 31)
    invoked from within
"my revision $page"
    (class "::Wiki" method "process" line 56)
    invoked from within
"$server process [string trim $uri /]"

-errorline

4