unknot.c 83 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980
  1. /*
  2. * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
  3. * http://www.trevorwishart.co.uk
  4. * http://www.composersdesktop.com
  5. *
  6. This file is part of the CDP System.
  7. The CDP System is free software; you can redistribute it
  8. and/or modify it under the terms of the GNU Lesser General Public
  9. License as published by the Free Software Foundation; either
  10. version 2.1 of the License, or (at your option) any later version.
  11. The CDP System is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU Lesser General Public License for more details.
  15. You should have received a copy of the GNU Lesser General Public
  16. License along with the CDP System; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  18. 02111-1307 USA
  19. *
  20. */
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <structures.h>
  24. #include <tkglobals.h>
  25. #include <pnames.h>
  26. #include <filetype.h>
  27. #include <processno.h>
  28. #include <modeno.h>
  29. #include <logic.h>
  30. #include <globcon.h>
  31. #include <cdpmain.h>
  32. #include <math.h>
  33. #include <mixxcon.h>
  34. #include <osbind.h>
  35. #include <standalone.h>
  36. #include <science.h>
  37. #include <ctype.h>
  38. #include <sfsys.h>
  39. #include <string.h>
  40. #include <srates.h>
  41. // modes
  42. #define DO_UNKNOT 0
  43. #define DO_KNOT 1
  44. #define KNOTCNT 2
  45. #define KNOT_REGULAR .1 // Difference in duration between events for the pulse to be deemed regular
  46. #ifdef unix
  47. #define round(x) lround((x))
  48. #endif
  49. char errstr[2400];
  50. #define celltime scalefact
  51. int anal_infiles = 1;
  52. int sloom = 0;
  53. int sloombatch = 0;
  54. const char* cdp_version = "7.0.0";
  55. //CDP LIB REPLACEMENTS
  56. static int unknot_param_preprocess(int *patterncnt,dataptr dz);
  57. static int setup_unknot_application(dataptr dz);
  58. static int setup_unknot_param_ranges_and_defaults(dataptr dz);
  59. static int handle_the_outfile(int *cmdlinecnt,char ***cmdline,dataptr dz);
  60. static int open_the_outfile(dataptr dz);
  61. static int setup_and_init_input_param_activity(dataptr dz,int tipc);
  62. static int setup_input_param_defaultval_stores(int tipc,aplptr ap);
  63. static int establish_application(dataptr dz);
  64. static int initialise_vflags(dataptr dz);
  65. static int setup_parameter_storage_and_constants(int storage_cnt,dataptr dz);
  66. static int initialise_is_int_and_no_brk_constants(int storage_cnt,dataptr dz);
  67. static int mark_parameter_types(dataptr dz,aplptr ap);
  68. //static int get_tk_cmdline_word(int *cmdlinecnt,char ***cmdline,char *q);
  69. static int get_the_process_no(char *prog_identifier_from_cmdline,dataptr dz);
  70. static int get_the_mode_from_cmdline(char *str,dataptr dz);
  71. static int setup_and_init_input_brktable_constants(dataptr dz,int brkcnt);
  72. static int open_all_infiles(char **cmdline, int *patterncnt, dataptr dz);
  73. static int open_special_infile(char *str, dataptr dz);
  74. static int unknot(int *patterncnt,int *knotdatacnt,double **spatpos,double **spatstep,double **comboarray,int *combopatterncnt,double **outdata,dataptr dz);
  75. static int pulse_regular(double a,double b,double minstep);
  76. static int pulse_more(double thisstep,double maxstep,double minerror);
  77. static int unknot_output(int *patterncnt,int knotdatacnt,double *spatpos,double *spatstep,double *comboarray,int combopatterncnt,double *outdata,dataptr dz);
  78. static void sortcomoboarray(int combopatterncnt,double *comboarray);
  79. static int setup_respatialisation_params(double *spatpos,double *spatstep,double *comboarray, int combopatterncnt,int respacecnt,dataptr dz);
  80. static int GenerateKnotCombo (double *comboarray,int combono,int *patterncnt,dataptr dz);
  81. static int IsAnIntegerInRange(char *str,int imin, int imax);
  82. static int IsAFilename(char *str);
  83. /**************************************** MAIN *********************************************/
  84. int main(int argc,char *argv[])
  85. {
  86. int exit_status, paramcnt = 0, test, OK, OK2, OK3;
  87. dataptr dz = NULL;
  88. char **cmdline, *p;
  89. int *patterncnt;
  90. int cmdlinecnt;
  91. int knotdatacnt;
  92. double *spatpos, *spatstep, *outdata, *comboarray, dummy;
  93. int combopatterncnt, n;
  94. aplptr ap;
  95. int is_launched = FALSE;
  96. if(argc==2 && (strcmp(argv[1],"--version") == 0)) {
  97. fprintf(stdout,"%s\n",cdp_version);
  98. fflush(stdout);
  99. return 0;
  100. }
  101. /* CHECK FOR SOUNDLOOM */
  102. if((sloom = sound_loom_in_use(&argc,&argv)) > 1) {
  103. sloom = 0;
  104. sloombatch = 1;
  105. }
  106. if(sflinit("cdp")){
  107. sfperror("cdp: initialisation\n");
  108. return(FAILED);
  109. }
  110. /* SET UP THE PRINCIPLE DATASTRUCTURE */
  111. if((exit_status = establish_datastructure(&dz))<0) { // CDP LIB
  112. print_messages_and_close_sndfiles(exit_status,is_launched,dz);
  113. return(FAILED);
  114. }
  115. if(argc == 1) {
  116. usage1();
  117. return(FAILED);
  118. } else if(argc == 2) {
  119. usage2(argv[1]);
  120. return(FAILED);
  121. }
  122. if((exit_status = make_initial_cmdline_check(&argc,&argv))<0) { // CDP LIB
  123. print_messages_and_close_sndfiles(exit_status,is_launched,dz);
  124. return(FAILED);
  125. }
  126. cmdline = argv;
  127. cmdlinecnt = argc;
  128. if((get_the_process_no(argv[0],dz))<0)
  129. return(FAILED);
  130. cmdline++;
  131. cmdlinecnt--;
  132. dz->maxmode = 3;
  133. if((exit_status = get_the_mode_from_cmdline(cmdline[0],dz))<0) {
  134. print_messages_and_close_sndfiles(exit_status,is_launched,dz);
  135. return(exit_status);
  136. }
  137. cmdline++;
  138. cmdlinecnt--;
  139. // setup_particular_application =
  140. if((exit_status = setup_unknot_application(dz))<0) {
  141. print_messages_and_close_sndfiles(exit_status,is_launched,dz);
  142. return(FAILED);
  143. }
  144. if((exit_status = count_and_allocate_for_infiles(cmdlinecnt,cmdline,dz))<0) { // CDP LIB
  145. print_messages_and_close_sndfiles(exit_status,is_launched,dz);
  146. return(FAILED);
  147. }
  148. ap = dz->application;
  149. // setup_param_ranges_and_defaults() =
  150. if((exit_status = setup_unknot_param_ranges_and_defaults(dz))<0) {
  151. exit_status = print_messages_and_close_sndfiles(exit_status,is_launched,dz);
  152. return(FAILED);
  153. }
  154. switch(dz->mode) {
  155. case(KNOTCNT): paramcnt = 0; break;
  156. default: paramcnt = 10; break;
  157. }
  158. n = argc - 1;
  159. while(argv[n][0] == '-') { // Count backwards over any flags
  160. paramcnt++; // And add these items to number of params on cmdline
  161. n--;
  162. }
  163. if((dz->infilecnt = cmdlinecnt - paramcnt) <= 0) {
  164. fprintf(stderr,"Too few parameters on cmdline.\n");
  165. return(FAILED);
  166. }
  167. test = 0;
  168. OK = 1;
  169. OK2 = 1;
  170. OK3 = 1;
  171. while(test < 8) {
  172. if(dz->mode == KNOTCNT) {
  173. if(!IsAFilename(argv[n]))
  174. OK3 = 0;
  175. } else {
  176. switch(test) {
  177. case(0):
  178. case(1):
  179. p = argv[n];
  180. if(!get_float_from_within_string(&p,&dummy))
  181. OK = 0;
  182. if(dummy < 0.0 || dummy > 8.0)
  183. OK = 0;
  184. break;
  185. case(2):
  186. if(!IsAnIntegerInRange(argv[n],0,5))
  187. OK2 = 0;
  188. break;
  189. case(4):
  190. if(!IsAnIntegerInRange(argv[n],1,256))
  191. OK2 = 0;
  192. break;
  193. case(3):
  194. case(5):
  195. case(6):
  196. case(7):
  197. if(!IsAnIntegerInRange(argv[n],0,256))
  198. OK2 = 0;
  199. break;
  200. }
  201. }
  202. if(!OK) {
  203. fprintf(stderr,"Invalid or out of range channel-range position (%s).\n\n",argv[n]);
  204. usage2("unknot");
  205. return(FAILED);
  206. }
  207. if(!OK2) {
  208. fprintf(stderr,"Invalid or out of range integer param (%s) (or too few integer params).\n\n",argv[n]);
  209. usage2("unknot");
  210. return(FAILED);
  211. }
  212. if(!OK3) {
  213. fprintf(stderr,"Invalid param (%s) (expecting file): possibly too many or too few params.\n\n",argv[n]);
  214. usage2("unknot");
  215. return(FAILED);
  216. }
  217. test++;
  218. n--;
  219. if(n < 3)
  220. break;
  221. }
  222. dz->ifd = NULL; // Prevents spurious attempts to close output soundfiles
  223. if((patterncnt = (int *)malloc(dz->infilecnt * sizeof(int)))==NULL) {
  224. fprintf(stderr,"setting up input file data counters.\n");
  225. return(FAILED);
  226. }
  227. if((exit_status = open_all_infiles(cmdline,patterncnt,dz))<0) {
  228. print_messages_and_close_sndfiles(exit_status,is_launched,dz);
  229. return(FAILED);
  230. }
  231. cmdline += dz->infilecnt;
  232. cmdlinecnt -= dz->infilecnt;
  233. // handle_outfile() =
  234. if(dz->mode != KNOTCNT) {
  235. if((exit_status = handle_the_outfile(&cmdlinecnt,&cmdline,dz))<0) {
  236. print_messages_and_close_sndfiles(exit_status,is_launched,dz);
  237. return(FAILED);
  238. }
  239. }
  240. // handle_formants() redundant
  241. // handle_formant_quiksearch() redundant
  242. // handle_special_data() redundant
  243. if(dz->mode != KNOTCNT) {
  244. if((exit_status = open_special_infile(cmdline[0],dz))<0) {
  245. print_messages_and_close_sndfiles(exit_status,is_launched,dz);
  246. return(FAILED);
  247. }
  248. cmdline++;
  249. cmdlinecnt--;
  250. }
  251. if((exit_status = read_parameters_and_flags(&cmdline,&cmdlinecnt,dz))<0) { // CDP LIB
  252. print_messages_and_close_sndfiles(exit_status,is_launched,dz);
  253. return(FAILED);
  254. }
  255. // check_param_validity_and_consistency....
  256. if((exit_status = unknot_param_preprocess(patterncnt,dz))<0) {
  257. print_messages_and_close_sndfiles(exit_status,is_launched,dz);
  258. return(FAILED);
  259. }
  260. is_launched = TRUE;
  261. //spec_process_file =
  262. if(dz->mode != KNOTCNT) {
  263. if((exit_status = open_the_outfile(dz))<0) {
  264. print_messages_and_close_sndfiles(exit_status,is_launched,dz);
  265. return(FAILED);
  266. }
  267. }
  268. if((exit_status = unknot(patterncnt,&knotdatacnt,&spatpos,&spatstep,&comboarray,&combopatterncnt,&outdata,dz))<0) {
  269. print_messages_and_close_sndfiles(exit_status,is_launched,dz);
  270. return(FAILED);
  271. }
  272. if(dz->mode != KNOTCNT) {
  273. if((exit_status = unknot_output(patterncnt,knotdatacnt,spatpos,spatstep,comboarray,combopatterncnt,outdata,dz))<0) {
  274. print_messages_and_close_sndfiles(exit_status,is_launched,dz);
  275. return(FAILED);
  276. }
  277. if((exit_status = complete_output(dz))<0) { // CDP LIB
  278. print_messages_and_close_sndfiles(exit_status,is_launched,dz);
  279. return(FAILED);
  280. }
  281. }
  282. exit_status = print_messages_and_close_sndfiles(FINISHED,is_launched,dz); // CDP LIB
  283. free(dz);
  284. return(SUCCEEDED);
  285. }
  286. /**********************************************
  287. REPLACED CDP LIB FUNCTIONS
  288. **********************************************/
  289. /****************************** SET_PARAM_DATA *********************************/
  290. int set_param_data(aplptr ap, int special_data,int maxparamcnt,int paramcnt,char *paramlist)
  291. {
  292. ap->special_data = (char)special_data;
  293. ap->param_cnt = (char)paramcnt;
  294. ap->max_param_cnt = (char)maxparamcnt;
  295. if(ap->max_param_cnt>0) {
  296. if((ap->param_list = (char *)malloc((size_t)(ap->max_param_cnt+1)))==NULL) {
  297. sprintf(errstr,"INSUFFICIENT MEMORY: for param_list\n");
  298. return(MEMORY_ERROR);
  299. }
  300. strcpy(ap->param_list,paramlist);
  301. }
  302. return(FINISHED);
  303. }
  304. /****************************** SET_VFLGS *********************************/
  305. int set_vflgs
  306. (aplptr ap,char *optflags,int optcnt,char *optlist,char *varflags,int vflagcnt, int vparamcnt,char *varlist)
  307. {
  308. ap->option_cnt = (char) optcnt; /*RWD added cast */
  309. if(optcnt) {
  310. if((ap->option_list = (char *)malloc((size_t)(optcnt+1)))==NULL) {
  311. sprintf(errstr,"INSUFFICIENT MEMORY: for option_list\n");
  312. return(MEMORY_ERROR);
  313. }
  314. strcpy(ap->option_list,optlist);
  315. if((ap->option_flags = (char *)malloc((size_t)(optcnt+1)))==NULL) {
  316. sprintf(errstr,"INSUFFICIENT MEMORY: for option_flags\n");
  317. return(MEMORY_ERROR);
  318. }
  319. strcpy(ap->option_flags,optflags);
  320. }
  321. ap->vflag_cnt = (char) vflagcnt;
  322. ap->variant_param_cnt = (char) vparamcnt;
  323. if(vflagcnt) {
  324. if((ap->variant_list = (char *)malloc((size_t)(vflagcnt+1)))==NULL) {
  325. sprintf(errstr,"INSUFFICIENT MEMORY: for variant_list\n");
  326. return(MEMORY_ERROR);
  327. }
  328. strcpy(ap->variant_list,varlist);
  329. if((ap->variant_flags = (char *)malloc((size_t)(vflagcnt+1)))==NULL) {
  330. sprintf(errstr,"INSUFFICIENT MEMORY: for variant_flags\n");
  331. return(MEMORY_ERROR);
  332. }
  333. strcpy(ap->variant_flags,varflags);
  334. }
  335. return(FINISHED);
  336. }
  337. /***************************** APPLICATION_INIT **************************/
  338. int application_init(dataptr dz)
  339. {
  340. int exit_status;
  341. int storage_cnt;
  342. int tipc, brkcnt;
  343. aplptr ap = dz->application;
  344. if(ap->vflag_cnt>0)
  345. initialise_vflags(dz);
  346. tipc = ap->max_param_cnt + ap->option_cnt + ap->variant_param_cnt;
  347. ap->total_input_param_cnt = (char)tipc;
  348. if(tipc>0) {
  349. if((exit_status = setup_input_param_range_stores(tipc,ap))<0)
  350. return(exit_status);
  351. if((exit_status = setup_input_param_defaultval_stores(tipc,ap))<0)
  352. return(exit_status);
  353. if((exit_status = setup_and_init_input_param_activity(dz,tipc))<0)
  354. return(exit_status);
  355. }
  356. brkcnt = tipc;
  357. dz->extrabrkno = brkcnt;
  358. brkcnt++; /* Required by CDP library logic for textfile input */
  359. // BUT THERE ARE NO INPUTFILE brktables USED IN THIS PROCESS
  360. if(brkcnt>0) {
  361. if((exit_status = setup_and_init_input_brktable_constants(dz,brkcnt))<0)
  362. return(exit_status);
  363. }
  364. if((storage_cnt = tipc + ap->internal_param_cnt)>0) {
  365. if((exit_status = setup_parameter_storage_and_constants(storage_cnt,dz))<0)
  366. return(exit_status);
  367. if((exit_status = initialise_is_int_and_no_brk_constants(storage_cnt,dz))<0)
  368. return(exit_status);
  369. }
  370. if((exit_status = mark_parameter_types(dz,ap))<0)
  371. return(exit_status);
  372. // establish_infile_constants() replaced by
  373. dz->infilecnt = -1; // Flags 1 or more infiles
  374. //establish_bufptrs_and_extra_buffers():
  375. return(FINISHED);
  376. }
  377. /********************** SETUP_PARAMETER_STORAGE_AND_CONSTANTS ********************/
  378. /* RWD mallo changed to calloc; helps debug verison run as release! */
  379. int setup_parameter_storage_and_constants(int storage_cnt,dataptr dz)
  380. {
  381. if((dz->param = (double *)calloc(storage_cnt, sizeof(double)))==NULL) {
  382. sprintf(errstr,"setup_parameter_storage_and_constants(): 1\n");
  383. return(MEMORY_ERROR);
  384. }
  385. if((dz->iparam = (int *)calloc(storage_cnt, sizeof(int) ))==NULL) {
  386. sprintf(errstr,"setup_parameter_storage_and_constants(): 2\n");
  387. return(MEMORY_ERROR);
  388. }
  389. if((dz->is_int = (char *)calloc(storage_cnt, sizeof(char)))==NULL) {
  390. sprintf(errstr,"setup_parameter_storage_and_constants(): 3\n");
  391. return(MEMORY_ERROR);
  392. }
  393. if((dz->no_brk = (char *)calloc(storage_cnt, sizeof(char)))==NULL) {
  394. sprintf(errstr,"setup_parameter_storage_and_constants(): 5\n");
  395. return(MEMORY_ERROR);
  396. }
  397. return(FINISHED);
  398. }
  399. /************** INITIALISE_IS_INT_AND_NO_BRK_CONSTANTS *****************/
  400. int initialise_is_int_and_no_brk_constants(int storage_cnt,dataptr dz)
  401. {
  402. int n;
  403. for(n=0;n<storage_cnt;n++) {
  404. dz->is_int[n] = (char)0;
  405. dz->no_brk[n] = (char)0;
  406. }
  407. return(FINISHED);
  408. }
  409. /***************************** MARK_PARAMETER_TYPES **************************/
  410. int mark_parameter_types(dataptr dz,aplptr ap)
  411. {
  412. int n, m; /* PARAMS */
  413. for(n=0;n<ap->max_param_cnt;n++) {
  414. switch(ap->param_list[n]) {
  415. case('0'): break; /* dz->is_active[n] = 0 is default */
  416. case('i'): dz->is_active[n] = (char)1; dz->is_int[n] = (char)1;dz->no_brk[n] = (char)1; break;
  417. case('I'): dz->is_active[n] = (char)1; dz->is_int[n] = (char)1; break;
  418. case('d'): dz->is_active[n] = (char)1; dz->no_brk[n] = (char)1; break;
  419. case('D'): dz->is_active[n] = (char)1; /* normal case: double val or brkpnt file */ break;
  420. default:
  421. sprintf(errstr,"Programming error: invalid parameter type in mark_parameter_types()\n");
  422. return(PROGRAM_ERROR);
  423. }
  424. } /* OPTIONS */
  425. for(n=0,m=ap->max_param_cnt;n<ap->option_cnt;n++,m++) {
  426. switch(ap->option_list[n]) {
  427. case('i'): dz->is_active[m] = (char)1; dz->is_int[m] = (char)1; dz->no_brk[m] = (char)1; break;
  428. case('I'): dz->is_active[m] = (char)1; dz->is_int[m] = (char)1; break;
  429. case('d'): dz->is_active[m] = (char)1; dz->no_brk[m] = (char)1; break;
  430. case('D'): dz->is_active[m] = (char)1; /* normal case: double val or brkpnt file */ break;
  431. default:
  432. sprintf(errstr,"Programming error: invalid option type in mark_parameter_types()\n");
  433. return(PROGRAM_ERROR);
  434. }
  435. } /* VARIANTS */
  436. for(n=0,m=ap->max_param_cnt + ap->option_cnt;n < ap->variant_param_cnt; n++, m++) {
  437. switch(ap->variant_list[n]) {
  438. case('0'): break;
  439. case('i'): dz->is_active[m] = (char)1; dz->is_int[m] = (char)1; dz->no_brk[m] = (char)1; break;
  440. case('I'): dz->is_active[m] = (char)1; dz->is_int[m] = (char)1; break;
  441. case('d'): dz->is_active[m] = (char)1; dz->no_brk[m] = (char)1; break;
  442. case('D'): dz->is_active[m] = (char)1; /* normal case: double val or brkpnt file */ break;
  443. default:
  444. sprintf(errstr,"Programming error: invalid variant type in mark_parameter_types()\n");
  445. return(PROGRAM_ERROR);
  446. }
  447. } /* INTERNAL */
  448. for(n=0,
  449. m=ap->max_param_cnt + ap->option_cnt + ap->variant_param_cnt; n<ap->internal_param_cnt; n++,m++) {
  450. switch(ap->internal_param_list[n]) {
  451. case('0'): break; /* dummy variables: variables not used: but important for internal paream numbering!! */
  452. case('i'): dz->is_int[m] = (char)1; dz->no_brk[m] = (char)1; break;
  453. case('d'): dz->no_brk[m] = (char)1; break;
  454. default:
  455. sprintf(errstr,"Programming error: invalid internal param type in mark_parameter_types()\n");
  456. return(PROGRAM_ERROR);
  457. }
  458. }
  459. return(FINISHED);
  460. }
  461. /************************ HANDLE_THE_OUTFILE *********************/
  462. int handle_the_outfile(int *cmdlinecnt,char ***cmdline,dataptr dz)
  463. {
  464. char *filename = (*cmdline)[0];
  465. if(file_has_invalid_startchar(filename) || value_is_numeric(filename)) {
  466. sprintf(errstr,"Outfile name %s has invalid start character(s) or looks too much like a number.\n",filename);
  467. return(DATA_ERROR);
  468. }
  469. strcpy(dz->outfilename,filename);
  470. (*cmdline)++;
  471. (*cmdlinecnt)--;
  472. return(FINISHED);
  473. }
  474. /************************ OPEN_THE_OUTFILE *********************/
  475. int open_the_outfile(dataptr dz)
  476. {
  477. int exit_status;
  478. if((exit_status = create_sized_outfile(dz->outfilename,dz))<0)
  479. return(exit_status);
  480. return(FINISHED);
  481. }
  482. /***************************** ESTABLISH_APPLICATION **************************/
  483. int establish_application(dataptr dz)
  484. {
  485. aplptr ap;
  486. if((dz->application = (aplptr)malloc(sizeof (struct applic)))==NULL) {
  487. sprintf(errstr,"establish_application()\n");
  488. return(MEMORY_ERROR);
  489. }
  490. ap = dz->application;
  491. memset((char *)ap,0,sizeof(struct applic));
  492. return(FINISHED);
  493. }
  494. /************************* INITIALISE_VFLAGS *************************/
  495. int initialise_vflags(dataptr dz)
  496. {
  497. int n;
  498. if((dz->vflag = (char *)malloc(dz->application->vflag_cnt * sizeof(char)))==NULL) {
  499. sprintf(errstr,"INSUFFICIENT MEMORY: vflag store,\n");
  500. return(MEMORY_ERROR);
  501. }
  502. for(n=0;n<dz->application->vflag_cnt;n++)
  503. dz->vflag[n] = FALSE;
  504. return FINISHED;
  505. }
  506. /************************* SETUP_INPUT_PARAM_DEFAULTVALS *************************/
  507. int setup_input_param_defaultval_stores(int tipc,aplptr ap)
  508. {
  509. int n;
  510. if((ap->default_val = (double *)malloc(tipc * sizeof(double)))==NULL) {
  511. sprintf(errstr,"INSUFFICIENT MEMORY for application default values store\n");
  512. return(MEMORY_ERROR);
  513. }
  514. for(n=0;n<tipc;n++)
  515. ap->default_val[n] = 0.0;
  516. return(FINISHED);
  517. }
  518. /***************************** SETUP_AND_INIT_INPUT_PARAM_ACTIVITY **************************/
  519. int setup_and_init_input_param_activity(dataptr dz,int tipc)
  520. {
  521. int n;
  522. if((dz->is_active = (char *)malloc((size_t)tipc))==NULL) {
  523. sprintf(errstr,"setup_and_init_input_param_activity()\n");
  524. return(MEMORY_ERROR);
  525. }
  526. for(n=0;n<tipc;n++)
  527. dz->is_active[n] = (char)0;
  528. return(FINISHED);
  529. }
  530. /************************* SETUP_UNKNOT_APPLICATION *******************/
  531. int setup_unknot_application(dataptr dz)
  532. {
  533. int exit_status;
  534. aplptr ap;
  535. if((exit_status = establish_application(dz))<0) // GLOBAL
  536. return(FAILED);
  537. ap = dz->application;
  538. // SEE parstruct FOR EXPLANATION of next 2 functions
  539. switch(dz->mode) {
  540. case(DO_UNKNOT):
  541. case(DO_KNOT): exit_status = set_param_data(ap,0,8,8,"iiiiiidd"); break;
  542. case(KNOTCNT): exit_status = set_param_data(ap,0,8,0,"00000000"); break;
  543. }
  544. if(exit_status < 0)
  545. return(FAILED);
  546. if(dz->mode == KNOTCNT)
  547. exit_status = set_vflgs(ap,"",0,"","mct",3,2,"di0");
  548. else
  549. exit_status = set_vflgs(ap,"",0,"","mcte",4,2,"di00");
  550. if(exit_status < 0)
  551. return(FAILED);
  552. // set_legal_infile_structure -->
  553. dz->has_otherfile = FALSE;
  554. // assign_process_logic -->
  555. dz->input_data_type = ALL_FILES;
  556. dz->process_type = TO_TEXTFILE;
  557. dz->outfiletype = TEXTFILE_OUT;
  558. return application_init(dz); //GLOBAL
  559. }
  560. /************************* SETUP_UNKNOT_PARAM_RANGES_AND_DEFAULTS *******************/
  561. int setup_unknot_param_ranges_and_defaults(dataptr dz)
  562. {
  563. int exit_status;
  564. aplptr ap = dz->application;
  565. // set_param_ranges()
  566. ap->total_input_param_cnt = (char)(ap->max_param_cnt + ap->option_cnt + ap->variant_param_cnt);
  567. // NB total_input_param_cnt is > 0 !!!
  568. if((exit_status = setup_input_param_range_stores(ap->total_input_param_cnt,ap))<0)
  569. return(FAILED);
  570. // get_param_ranges()
  571. if(dz->mode != KNOTCNT) {
  572. ap->lo[KNOT_PATREP] = 0;
  573. ap->hi[KNOT_PATREP] = 256;
  574. ap->default_val[KNOT_PATREP] = 2;
  575. ap->lo[KNOT_COMBOREP] = 0;
  576. ap->hi[KNOT_COMBOREP] = 256;
  577. ap->default_val[KNOT_COMBOREP] = 2;
  578. ap->lo[KNOT_ALLREP] = 0;
  579. ap->hi[KNOT_ALLREP] = 256;
  580. ap->default_val[KNOT_ALLREP] = 2;
  581. ap->lo[KNOT_UNKNOTREP] = 1;
  582. ap->hi[KNOT_UNKNOTREP] = 256;
  583. ap->default_val[KNOT_UNKNOTREP] = 2;
  584. ap->lo[KNOT_GOALREP] = 0;
  585. ap->hi[KNOT_GOALREP] = 256;
  586. ap->default_val[KNOT_GOALREP] = 2;
  587. ap->lo[KNOT_SPACETYP] = 0;
  588. ap->hi[KNOT_SPACETYP] = 5;
  589. ap->default_val[KNOT_SPACETYP] = 0;
  590. ap->lo[KNOT_CHANA] = 0;
  591. ap->hi[KNOT_CHANA] = 8;
  592. ap->default_val[KNOT_CHANA] = 1;
  593. ap->lo[KNOT_CHANB] = 0;
  594. ap->hi[KNOT_CHANB] = 8;
  595. ap->default_val[KNOT_CHANB] = 1;
  596. }
  597. ap->lo[KNOT_MIN] = FLTERR;
  598. ap->hi[KNOT_MIN] = 0.1;
  599. ap->default_val[KNOT_MIN] = KNOT_REGULAR;
  600. ap->lo[KNOT_CLIP] = 1;
  601. ap->hi[KNOT_CLIP] = 16;
  602. ap->default_val[KNOT_CLIP] = 1;
  603. dz->maxmode = 3;
  604. put_default_vals_in_all_params(dz);
  605. return(FINISHED);
  606. }
  607. /************************* redundant functions: to ensure libs compile OK *******************/
  608. int assign_process_logic(dataptr dz)
  609. {
  610. return(FINISHED);
  611. }
  612. void set_legal_infile_structure(dataptr dz)
  613. {}
  614. int set_legal_internalparam_structure(int process,int mode,aplptr ap)
  615. {
  616. return(FINISHED);
  617. }
  618. int setup_internal_arrays_and_array_pointers(dataptr dz)
  619. {
  620. return(FINISHED);
  621. }
  622. int establish_bufptrs_and_extra_buffers(dataptr dz)
  623. {
  624. return(FINISHED);
  625. }
  626. int read_special_data(char *str,dataptr dz)
  627. {
  628. return(FINISHED);
  629. }
  630. int inner_loop
  631. (int *peakscore,int *descnt,int *in_start_portion,int *least,int *pitchcnt,int windows_in_buf,dataptr dz)
  632. {
  633. return(FINISHED);
  634. }
  635. int get_process_no(char *prog_identifier_from_cmdline,dataptr dz)
  636. {
  637. return(FINISHED);
  638. }
  639. /**************************** UNKNOT_PARAM_PREPROCESS *****************************/
  640. int unknot_param_preprocess(int *patterncnt,dataptr dz)
  641. {
  642. int n;
  643. int endtimeloc, warned = 0;
  644. double endtime = 0.0;
  645. for(n=0;n<dz->infilecnt;n++) {
  646. endtimeloc = (patterncnt[n] - 1) * 4;
  647. if(n==0)
  648. endtime = dz->parray[n][endtimeloc];
  649. else if(!flteq(endtime,dz->parray[n][endtimeloc])) {
  650. if(!warned) {
  651. fprintf(stdout,"WARNING: PATTERNS DO NOT ALL END IN SYNC.\n");
  652. fflush(stdout);
  653. warned = 1;
  654. }
  655. endtime = max(endtime,dz->parray[n][endtimeloc]);
  656. }
  657. }
  658. dz->celltime = endtime;
  659. if(dz->mode == KNOTCNT) {
  660. dz->iparam[KNOT_PATREP] = 0;
  661. dz->iparam[KNOT_COMBOREP] = 0;
  662. dz->iparam[KNOT_ALLREP] = 0;
  663. dz->iparam[KNOT_UNKNOTREP] = 0;
  664. dz->iparam[KNOT_GOALREP] = 0;
  665. dz->iparam[KNOT_SPACETYP] = 0;
  666. dz->iparam[KNOT_CHANA] = 0;
  667. dz->iparam[KNOT_CHANB] = 0;
  668. } else {
  669. if(dz->param[KNOT_CHANA] < 1.0)
  670. dz->param[KNOT_CHANA] += 8.0; // Change range from 0 to 8, to 1 to < 9.0
  671. dz->param[KNOT_CHANA] -= 1.0; // Change range to 0 to < 8.0 (allows modulo-8 arithmetic)
  672. if(dz->param[KNOT_CHANB] < 1.0)
  673. dz->param[KNOT_CHANB] += 8.0;
  674. dz->param[KNOT_CHANB] -= 1.0;
  675. }
  676. return FINISHED;
  677. }
  678. /********************************************************************************************/
  679. int get_the_process_no(char *prog_identifier_from_cmdline,dataptr dz)
  680. {
  681. if(!strcmp(prog_identifier_from_cmdline,"unknot")) dz->process = UNKNOT;
  682. else {
  683. sprintf(errstr,"Unknown program identification string '%s'\n",prog_identifier_from_cmdline);
  684. return(USAGE_ONLY);
  685. }
  686. return(FINISHED);
  687. }
  688. /******************************** SETUP_AND_INIT_INPUT_BRKTABLE_CONSTANTS ********************************/
  689. int setup_and_init_input_brktable_constants(dataptr dz,int brkcnt)
  690. {
  691. int n;
  692. if((dz->brk = (double **)malloc(brkcnt * sizeof(double *)))==NULL) {
  693. sprintf(errstr,"setup_and_init_input_brktable_constants(): 1\n");
  694. return(MEMORY_ERROR);
  695. }
  696. if((dz->brkptr = (double **)malloc(brkcnt * sizeof(double *)))==NULL) {
  697. sprintf(errstr,"setup_and_init_input_brktable_constants(): 6\n");
  698. return(MEMORY_ERROR);
  699. }
  700. if((dz->brksize = (int *)malloc(brkcnt * sizeof(int)))==NULL) {
  701. sprintf(errstr,"setup_and_init_input_brktable_constants(): 2\n");
  702. return(MEMORY_ERROR);
  703. }
  704. if((dz->firstval = (double *)malloc(brkcnt * sizeof(double)))==NULL) {
  705. sprintf(errstr,"setup_and_init_input_brktable_constants(): 3\n");
  706. return(MEMORY_ERROR);
  707. }
  708. if((dz->lastind = (double *)malloc(brkcnt * sizeof(double)))==NULL) {
  709. sprintf(errstr,"setup_and_init_input_brktable_constants(): 4\n");
  710. return(MEMORY_ERROR);
  711. }
  712. if((dz->lastval = (double *)malloc(brkcnt * sizeof(double)))==NULL) {
  713. sprintf(errstr,"setup_and_init_input_brktable_constants(): 5\n");
  714. return(MEMORY_ERROR);
  715. }
  716. if((dz->brkinit = (int *)malloc(brkcnt * sizeof(int)))==NULL) {
  717. sprintf(errstr,"setup_and_init_input_brktable_constants(): 7\n");
  718. return(MEMORY_ERROR);
  719. }
  720. for(n=0;n<brkcnt;n++) {
  721. dz->brk[n] = NULL;
  722. dz->brkptr[n] = NULL;
  723. dz->brkinit[n] = 0;
  724. dz->brksize[n] = 0;
  725. }
  726. return(FINISHED);
  727. }
  728. /****************************** GET_MODE *********************************/
  729. int get_the_mode_from_cmdline(char *str,dataptr dz)
  730. {
  731. char temp[200], *p;
  732. if(sscanf(str,"%s",temp)!=1) {
  733. sprintf(errstr,"Cannot read mode of program.\n");
  734. return(USAGE_ONLY);
  735. }
  736. p = temp + strlen(temp) - 1;
  737. while(p >= temp) {
  738. if(!isdigit(*p)) {
  739. fprintf(stderr,"Invalid mode of program entered.\n");
  740. return(USAGE_ONLY);
  741. }
  742. p--;
  743. }
  744. if(sscanf(str,"%d",&dz->mode)!=1) {
  745. fprintf(stderr,"Cannot read mode of program.\n");
  746. return(USAGE_ONLY);
  747. }
  748. if(dz->mode <= 0 || dz->mode > dz->maxmode) {
  749. fprintf(stderr,"Program mode value [%d] is out of range [1 - %d].\n",dz->mode,dz->maxmode);
  750. return(USAGE_ONLY);
  751. }
  752. dz->mode--; /* CHANGE TO INTERNAL REPRESENTATION OF MODE NO */
  753. return(FINISHED);
  754. }
  755. /******************************** USAGE1 ********************************/
  756. int usage1(void)
  757. {
  758. usage2("unknot");
  759. return(USAGE_ONLY);
  760. }
  761. /******************************** USAGE2 ********************************/
  762. int usage2(char *str)
  763. {
  764. if(!strcmp(str,"unknot")) {
  765. fprintf(stdout,
  766. "USAGE: unknot unknot 1-2 inf1 inf2 [inf3 ...] "
  767. " outfile combos r_pats r_combos r_all r_unknots r_goal spacetyp cha chb ....\n"
  768. "OR: unknot unknot 3 inf1 inf2 [inf3 ...] ....\n "
  769. "[-mmin] [-cclip] [-e] [-t]\n"
  770. "\n"
  771. "Takes set of textfiles, representing rhythmic patterns, creating combined pattern,\n"
  772. "repeating this, gradually unknotting it to regular timepulse & spatial distribution.\n"
  773. "MODES:\n"
  774. "1) Unknots (Events gradually moved, in turn, to be time & space equidistant).\n"
  775. "2) Knots (Runs process in reverse).\n"
  776. "3) Counts unknotting steps (No output).\n"
  777. "There are 5 (possible) stages to the unknotting process....\n"
  778. "(1) Repeat (each) original pattern (optional).\n"
  779. "(2) Repeat (each) specified combination of patterns (optional).\n"
  780. "(3) Repeat the combination of all patterns (optional).\n"
  781. "(4) Unknot the combined pattern.\n"
  782. "(5) Repeat the unknotted pattern (optional).\n"
  783. "Input patterns have lines each with 4 entries \"time MIDI level pos\"\n"
  784. "time : must start at zero and not decrease.\n"
  785. "MIDI : vals between 0 & 127, where convention is 0 indicates a silent file.\n"
  786. "level: lies between >0 and 1.\n"
  787. "pos : position in an 8-channel space, range 0 to 8 (fractional values OK).\n"
  788. "PARAMETERS:\n"
  789. "COMBOS Textfile List of pattern combos to use. (or zero, if no combos used)\n"
  790. " Each line lists 2 or more patterns to combine.\n"
  791. "Number of repetitions of......\n"
  792. "R_PATS each original pattern (Unknot, placed at start : Knot, placed at end).\n"
  793. "R_COMBOS each pattern combination.(Unknot, placed next : Knot, placed penultimate).\n"
  794. "R_ALL combined initial pattern.\n"
  795. "R_UNKNOTS each unknotting/knotting step.\n"
  796. "R_GOAL goal pattern.\n"
  797. "SPACETYP Type of spatial distribution for unknotted pattern.\n"
  798. " 0 No spatial redistribution. 3 Rotate anticlock between channels.\n"
  799. " 1 Alternating between channels. 4 Rotate clock-anticlock between channels.\n"
  800. " 2 Rotate clockwise between chans. 5 Rotate anticlock-clock between channels.\n"
  801. "(Redistributions to mono, tutti etc, can be made by a mix to mono, & crossfading).\n"
  802. "CHA First channel for spacetyp redistribution.\n"
  803. "CHB Second channel for spacetyp redistribution.\n"
  804. "MIN Event-Duration-differences read as \"zero\" (pulse \"regular\" = unknotted).\n"
  805. "CLIP Number of events to reposition at each (un)knotting step (default 1).\n"
  806. "-e Spatial redistribution starts at (un)knotting end.\n"
  807. " (default: ....starts at (un)knotting start.)\n"
  808. "-t Output data with titles and spacing to identify patterns being output.\n");
  809. } else
  810. fprintf(stdout,"Unknown option '%s'\n",str);
  811. return(USAGE_ONLY);
  812. }
  813. /******************************** USAGE3 ********************************/
  814. int usage3(char *str1,char *str2)
  815. {
  816. fprintf(stderr,"Insufficient parameters on command line.\n");
  817. return(USAGE_ONLY);
  818. }
  819. /******************************** OPEN_ALL_INFILES ********************************/
  820. int open_all_infiles(char **cmdline, int *patterncnt, dataptr dz)
  821. {
  822. int n, linecnt, cnt, idummy;
  823. double lasttime, dummy;
  824. FILE *fp;
  825. char temp[400], *p;
  826. if((dz->parray = (double **)malloc(dz->infilecnt * sizeof(double *)))==NULL) {
  827. sprintf(errstr,"INSUFFICIENT MEMORY pattern storage integer arrays.\n");
  828. return(MEMORY_ERROR);
  829. }
  830. for(n = 0; n < dz->infilecnt;n++) {
  831. if((fp = fopen(cmdline[n],"r"))==NULL) {
  832. sprintf(errstr,"Cannot open file %s to read pattern data. (Check usage)\n",cmdline[n]);
  833. return(DATA_ERROR);
  834. }
  835. patterncnt[n] = 0;
  836. linecnt = 1;
  837. lasttime = -1.0;
  838. while(fgets(temp,400,fp)!=NULL) {
  839. p = temp;
  840. while(isspace(*p))
  841. p++;
  842. if(*p == ';' || *p == ENDOFSTR) // Allow comments in file
  843. continue;
  844. cnt = 0;
  845. while(get_float_from_within_string(&p,&dummy)) {
  846. switch(cnt) {
  847. case(0):
  848. if(linecnt == 1 && dummy != 0.0) {
  849. sprintf(errstr,"FILE %s does not begin at time zero\n",cmdline[n]);
  850. return(DATA_ERROR);
  851. }
  852. if(dummy < lasttime) {
  853. sprintf(errstr,"FILE %s does not advance between times %lf and %lf\n",cmdline[n],lasttime,dummy);
  854. return(DATA_ERROR);
  855. }
  856. lasttime = dummy;
  857. break;
  858. case(1):
  859. idummy = (int)round(dummy);
  860. if(idummy != dummy) {
  861. sprintf(errstr,"FILE %s has non-integer MIDI value (%lf) at time %lf\n",cmdline[n],dummy,lasttime);
  862. return(DATA_ERROR);
  863. }
  864. if(idummy < 0 || idummy > 127) {
  865. sprintf(errstr,"FILE %s has out of range MIDI value (%d) at time %lf\n",cmdline[n],idummy,lasttime);
  866. return(DATA_ERROR);
  867. }
  868. break;
  869. case(2):
  870. if(dummy <= 0 || dummy > 1.0) {
  871. sprintf(errstr,"FILE %s has out of range LEVEL value (%lf) at time %lf\n",cmdline[n],dummy,lasttime);
  872. return(DATA_ERROR);
  873. }
  874. break;
  875. case(3):
  876. if(dummy < 0 || dummy > 8.0) {
  877. sprintf(errstr,"FILE %s has out of range POSITION value (%lf) at time %lf\n",cmdline[n],dummy,lasttime);
  878. return(DATA_ERROR);
  879. }
  880. break;
  881. default:
  882. sprintf(errstr,"FILE %s has too many values on line %d\n",cmdline[n],linecnt);
  883. return(DATA_ERROR);
  884. break;
  885. }
  886. cnt++;
  887. patterncnt[n]++;
  888. }
  889. if(cnt != 4) {
  890. sprintf(errstr,"FILE %s has too few values on line %d (should be 4)\n",cmdline[n],linecnt);
  891. return(DATA_ERROR);
  892. break;
  893. }
  894. linecnt++;
  895. }
  896. fseek(fp,0,0);
  897. if((dz->parray[n] = (double *)malloc(patterncnt[n] * sizeof(double)))==NULL) {
  898. sprintf(errstr,"INSUFFICIENT MEMORY for pattern %d data.\n",n+1);
  899. return(MEMORY_ERROR);
  900. }
  901. cnt = 0;
  902. while(fgets(temp,400,fp)!=NULL) {
  903. p = temp;
  904. while(isspace(*p))
  905. p++;
  906. if(*p == ';' || *p == ENDOFSTR) // Allow comments in file
  907. continue;
  908. while(get_float_from_within_string(&p,&dummy))
  909. dz->parray[n][cnt++] = dummy;
  910. }
  911. patterncnt[n] /= 4; // 4 entries per line in pattern
  912. fclose(fp);
  913. }
  914. return FINISHED;
  915. }
  916. /******************************** OPEN_SPECIAL_INFILE ********************************/
  917. int open_special_infile(char *str, dataptr dz)
  918. {
  919. int linecnt, cnt, kcnt, idummy;
  920. double dummy;
  921. FILE *fp;
  922. char temp[400], *p;
  923. int *gpcnts, *gpcheck;
  924. if (!strcmp(str,"0")) {
  925. dz->itemcnt = 0;
  926. return FINISHED;
  927. }
  928. if((gpcheck = (int *)malloc(dz->infilecnt * sizeof(int)))==NULL) {
  929. sprintf(errstr,"INSUFFICIENT MEMORY for pattern checking.\n");
  930. return(MEMORY_ERROR);
  931. }
  932. if((fp = fopen(str,"r"))==NULL) {
  933. sprintf(errstr,"Cannot open file %s to read pattern data.\n",str);
  934. return(DATA_ERROR);
  935. }
  936. linecnt = 0;
  937. while(fgets(temp,400,fp)!=NULL) {
  938. p = temp;
  939. while(isspace(*p))
  940. p++;
  941. if(*p == ';' || *p == ENDOFSTR) // Allow comments in file
  942. continue;
  943. cnt = 0;
  944. while(get_float_from_within_string(&p,&dummy)) {
  945. if (cnt >= dz->infilecnt) {
  946. sprintf(errstr,"TOO MANY ITEMS (%d) IN GROUPING ON LINE %d IN FILE %s\n",cnt+1,linecnt+1,str);
  947. return(DATA_ERROR);
  948. }
  949. idummy = (int)round(dummy);
  950. if(idummy < 1 || idummy > dz->infilecnt) {
  951. sprintf(errstr,"PATTERN MEMBER \"%d\" OUT OF RANGE (1 - %d) IN FILE %s\n",idummy,dz->infilecnt,str);
  952. return(DATA_ERROR);
  953. }
  954. gpcheck[cnt] = idummy;
  955. kcnt = cnt-1;
  956. while(kcnt >= 0) {
  957. if(gpcheck[cnt] == gpcheck[kcnt]) {
  958. sprintf(errstr,"ITEM \"%d\" DUPLICATED IN LINE %d IN FILE %s\n",gpcheck[cnt],linecnt+1,str);
  959. return(DATA_ERROR);
  960. }
  961. kcnt--;
  962. }
  963. cnt++;
  964. }
  965. if(cnt < 2) {
  966. sprintf(errstr,"LINE %d IN FILE %s HAS ONLT ONE ENTRY (MUST BE AT LEAST 2)\n",linecnt+1,str);
  967. return(DATA_ERROR);
  968. }
  969. linecnt++;
  970. }
  971. if(linecnt <= 0) {
  972. sprintf(errstr,"NO DATA FOUND IN FILE %s.\n",str);
  973. return(DATA_ERROR);
  974. }
  975. dz->itemcnt = linecnt;
  976. if((dz->iparray = (int **)malloc((dz->itemcnt+1) * sizeof(int *)))==NULL) {
  977. sprintf(errstr,"INSUFFICIENT MEMORY for pattern groupings.\n");
  978. return(MEMORY_ERROR);
  979. }
  980. if((dz->iparray[dz->itemcnt] = (int *)malloc(dz->itemcnt * sizeof(int)))==NULL) {
  981. sprintf(errstr,"INSUFFICIENT MEMORY for pattern grouping %d\n",linecnt+1);
  982. return(MEMORY_ERROR);
  983. }
  984. gpcnts = dz->iparray[dz->itemcnt];
  985. fseek(fp,0,0);
  986. linecnt = 0;
  987. while(fgets(temp,400,fp)!=NULL) {
  988. p = temp;
  989. while(isspace(*p))
  990. p++;
  991. if(*p == ';' || *p == ENDOFSTR) // Allow comments in file
  992. continue;
  993. cnt = 0;
  994. while(get_float_from_within_string(&p,&dummy))
  995. cnt++;
  996. gpcnts[linecnt] = cnt;
  997. if((dz->iparray[linecnt] = (int *)malloc(cnt * sizeof(int)))==NULL) {
  998. sprintf(errstr,"INSUFFICIENT MEMORY for pattern grouping %d\n",linecnt+1);
  999. return(MEMORY_ERROR);
  1000. }
  1001. linecnt++;
  1002. }
  1003. fseek(fp,0,0);
  1004. linecnt = 0;
  1005. while(fgets(temp,400,fp)!=NULL) {
  1006. p = temp;
  1007. while(isspace(*p))
  1008. p++;
  1009. if(*p == ';' || *p == ENDOFSTR) // Allow comments in file
  1010. continue;
  1011. cnt = 0;
  1012. while(get_float_from_within_string(&p,&dummy)) {
  1013. dz->iparray[linecnt][cnt] = (int)round(dummy);
  1014. cnt++;
  1015. }
  1016. linecnt++;
  1017. }
  1018. fclose(fp);
  1019. return FINISHED;
  1020. }
  1021. /******************************** UNKNOT **********************************
  1022. *
  1023. * dz->parray[0] to dz->parray[dz->infilecnt-1] contain all input patterns (in sets of 4 values)
  1024. * patterncnt[n] contains no of LINES in pattern n (4 items per"line") so arraysizes are patterncnt[n]*4
  1025. * Data in arrays interleaved as as "time MIDI level position"
  1026. * itemcnt = number of combos (for initial play of combos)
  1027. * dz->iparray[dz->itemcnt] contains the sizes of each combo
  1028. * dz->iparray[0] to dz->iparray[itemcnt-1] contains the actual combo
  1029. *
  1030. * celltime is duration of cell to be unknotted.
  1031. */
  1032. int unknot(int *patterncnt,int *knotdatacnt,double **spat_pos,double **spat_step,double **combo_array,int *combo_patterncnt,double **out_data,dataptr dz)
  1033. {
  1034. double *timediff, *comboarray, *outdata = NULL, *spatpos, *spatstep, *outpos;
  1035. int comboarraysize, outdiffcnt, outtestcnt, unknotting_eventcnt, outpatterncnt, outdatacnt = 0;
  1036. int n, m, r, k, tn, tm, tnow, tnext, tlast, passno, smooth, combopatterncnt, lastnonzerodiff;
  1037. int unknotcnt = 0, maxcnt, adjacent, zerocnt = 0, prezerocnt, postzerocnt, adjacentzeros, maxloc, respacecnt = 0;
  1038. double tim_n, mid_n, lev_n, pos_n, tim_m, mid_m, lev_m, pos_m;
  1039. double bastime, maxdiff, span, halfspan, sum;
  1040. int spacetyp = dz->iparam[KNOT_SPACETYP];
  1041. int writesteps = 0;
  1042. combopatterncnt = 0;
  1043. for(n=0;n < dz->infilecnt;n++)
  1044. combopatterncnt += patterncnt[n] - 1; // Count total number of events in combined pattern
  1045. *combo_patterncnt = combopatterncnt;
  1046. comboarraysize = combopatterncnt * 4;
  1047. if((*combo_array = (double *)malloc(comboarraysize * sizeof(double)))==NULL) {
  1048. sprintf(errstr,"Insufficient memory for output pattern.\n"); // Array to store combined pattern
  1049. return(MEMORY_ERROR);
  1050. }
  1051. comboarray = *combo_array;
  1052. if((timediff = (double *)malloc(combopatterncnt * sizeof(double)))==NULL) { // Array to store timesteps in combined pattern
  1053. sprintf(errstr,"Insufficient memory for output pattern.\n");
  1054. return(MEMORY_ERROR);
  1055. }
  1056. if((*spat_step = (double *)malloc(combopatterncnt * sizeof(double)))==NULL) { // Array to store spatial steps, for moving pattern element
  1057. sprintf(errstr,"Insufficient memory for output pattern.\n");
  1058. return(MEMORY_ERROR);
  1059. }
  1060. spatstep = *spat_step;
  1061. if((*spat_pos = (double *)malloc(combopatterncnt * sizeof(double)))==NULL) { // Array to spatial positions, as pattern elements are moved
  1062. sprintf(errstr,"Insufficient memory for output pattern.\n");
  1063. return(MEMORY_ERROR);
  1064. }
  1065. spatpos = *spat_pos;
  1066. if((outpos = (double *)malloc(combopatterncnt * sizeof(double)))==NULL) { // Array to spatial positions, as pattern elements are moved
  1067. sprintf(errstr,"Insufficient memory for output pattern.\n");
  1068. return(MEMORY_ERROR);
  1069. }
  1070. k = 0;
  1071. for(n=0;n < dz->infilecnt;n++) { // Copy all patterns into combination array
  1072. for(m=0;m < (patterncnt[n] - 1) * 4; m++) // But dropping endmarkers
  1073. comboarray[k++] = dz->parray[n][m];
  1074. }
  1075. sortcomoboarray(combopatterncnt,comboarray);
  1076. outdiffcnt = combopatterncnt - 1;
  1077. tnow = 0;
  1078. for(n= 0, tnext=4;n < outdiffcnt;n++,tnext+=4) { // Caculate and store timesteps in combined pattern
  1079. timediff[n] = comboarray[tnext] - comboarray[tnow];
  1080. tnow = tnext;
  1081. }
  1082. lastnonzerodiff = outdiffcnt-1;
  1083. for(n = outdiffcnt-1;n >= 0;n--) {
  1084. if(flteq(timediff[n],0.0)) { // Count zero steps (simultaneous events) in comobo-pattern
  1085. zerocnt++;
  1086. if(n == lastnonzerodiff)
  1087. lastnonzerodiff--;
  1088. }
  1089. }
  1090. if(outdiffcnt == zerocnt) {
  1091. sprintf(errstr,"ALL EVENTS ARE SYNCHRONOUS: CANNOT PROCEED\n");
  1092. return DATA_ERROR;
  1093. }
  1094. if(outdiffcnt - 1 == zerocnt) {
  1095. sprintf(errstr,"ALL EVENTS BUT ONE ARE SYNCHRONOUS: CANNOT PROCEED\n");
  1096. return DATA_ERROR;
  1097. }
  1098. outtestcnt = outdiffcnt - zerocnt; // How many time-steps to test, when checking result of unknotting step
  1099. for(passno = 0;passno<2;passno++) { // First pass assesses number of unknot steps and hence size of array
  1100. writesteps = 0;
  1101. if(passno > 0) {
  1102. tnow = 0;
  1103. for(n= 0, tnext=4;n < outdiffcnt;n++,tnext+=4) { // Reset original timediff vals
  1104. timediff[n] = comboarray[tnext] - comboarray[tnow];
  1105. tnow = tnext;
  1106. }
  1107. }
  1108. smooth = 0; // Second pass does the unknotting
  1109. outdatacnt = 0; // Count the size of the output array
  1110. bastime = 0.0; // Start-time of each pattern, as unknotting takes place
  1111. unknotcnt = 0; // Count the number of unknotting steps
  1112. while(!smooth) {
  1113. maxdiff = -1; // Preset maximum step between events
  1114. maxcnt = 0; // Count number of steps having the maximum value
  1115. adjacent = 0; // Count the number of steps equal-and-adjacent to the current maximum step
  1116. zerocnt = 0; // Count any run of zero-steps (event-sumultaneities)
  1117. prezerocnt = 0; // Remember number of zero-steps immediately prior to maximum step
  1118. postzerocnt = 0; // Remember number of zero steps immediately after a maximum step
  1119. adjacentzeros = 0; // Remember number of zero steps immediately prior to any maximum step equal-and-adjacent to the current maximum step
  1120. maxloc = 0; // Initialise location of found maximum step
  1121. for(n = 0;n < outdiffcnt;n++) {
  1122. if(flteq(timediff[n],0.0)) { // Skip, but count, zero steps
  1123. zerocnt++; // Count zeros
  1124. if(maxloc + postzerocnt == n-1) // If previous value was the maximum, or a zero-following-a-maximum
  1125. postzerocnt++; // count zeros AFTER a maximum
  1126. } else if(pulse_more(timediff[n],maxdiff,dz->param[KNOT_MIN])) { // If this is a maximum
  1127. maxdiff = timediff[n]; // remember size
  1128. maxloc = n; // and location
  1129. maxcnt = 1; // And start count of number of maxima with this value
  1130. adjacent = 0; // Number of adjacent maxima with this value (yet)
  1131. adjacentzeros = 0; // There are not yet adjacent maxima, so no zeros pre-adjacent maxima
  1132. prezerocnt = zerocnt; // Remember Number of preceding zerosteps
  1133. zerocnt = 0; // Reset zerocounter
  1134. postzerocnt = 0; // No zeros AFTER the current maximum (yet)
  1135. } else if(pulse_regular(timediff[n],maxdiff,dz->param[KNOT_MIN])) { // If this is "equal" to the current maximum
  1136. if(n == maxloc+postzerocnt+1) { // If minimum adjacent to current min or separated from it solely by zeros
  1137. adjacent += postzerocnt+1; // count the adjacent maxima and zeros
  1138. adjacentzeros = prezerocnt; // and if zeros adjacent to first of adjacent-maxima, remember this
  1139. postzerocnt = 0; // Reset zeros AFTER current min to 0
  1140. } else { // If new maximum is not next to previous one
  1141. adjacent = 0; // no adjacent maxima here (yet),
  1142. adjacentzeros = 0; // therefore no zeros adjacent to adjacent-maxima
  1143. prezerocnt = zerocnt; // Remember Number of preceding zerosteps
  1144. }
  1145. maxloc = n; // Remember the time-latest of the adjacent maxima
  1146. maxcnt++; // Count the maxima with this value
  1147. zerocnt = 0; // Reset zerocounter
  1148. postzerocnt = 0; // No zeros AFTER the current maximum (yet)
  1149. } else {
  1150. zerocnt = 0; // postzerocnt is NOT reset, as this is remembering
  1151. }
  1152. // any set of zeros after last maximum found.
  1153. // prezerocnt is NOT reset, as this is remembering
  1154. // any set of zeros prior to last maximum found.
  1155. }
  1156. if(maxcnt == outtestcnt) { // If all steps are equivalent
  1157. if(unknotcnt == 0) {
  1158. sprintf(errstr,"INITIAL PATTERN IS ALREADY UNKNOTTED\n");
  1159. return DATA_ERROR;
  1160. }
  1161. smooth = 1; // process is complete.
  1162. }
  1163. if(!smooth) {
  1164. if(maxloc == prezerocnt) { // isolated maximum at start, (or after ALL-zero steps)
  1165. if(maxloc+postzerocnt+1 >= outdiffcnt) {
  1166. sprintf(errstr,"ERROR IN SEGMENT ACCOUNTING 1\n");
  1167. return(PROGRAM_ERROR);
  1168. } // Span time-interval and one ABOVE (ignoring intervening zero-steps)
  1169. span = timediff[maxloc] + timediff[maxloc+postzerocnt+1];
  1170. halfspan = span/2.0; // Find average
  1171. timediff[maxloc] = halfspan; // Equalise the time-differences
  1172. timediff[maxloc+postzerocnt+1] = halfspan;
  1173. } else if(maxloc == lastnonzerodiff) { // maximum at top edge
  1174. if(adjacent) { // if adjacent to others
  1175. maxloc -= adjacent; // Find earliest maxdiff segment
  1176. prezerocnt = adjacentzeros; // Find any zeros immediately prior to this
  1177. }
  1178. // Span time-intervals and one BELOW (ignoring any intervening zero-steps)
  1179. if(maxloc-prezerocnt-1 < 0) {
  1180. sprintf(errstr,"ERROR IN SEGMENT ACCOUNTING 2\n");
  1181. return(PROGRAM_ERROR);
  1182. }
  1183. span = timediff[maxloc] + timediff[maxloc-prezerocnt-1];
  1184. halfspan = span/2.0; // Find average
  1185. timediff[maxloc-prezerocnt-1] = halfspan; // Equalise the time-differences
  1186. timediff[maxloc] = halfspan;
  1187. // maximum not at edge
  1188. } else {
  1189. if(maxloc+postzerocnt+1 < outdiffcnt) { // Span max seg and one ABOVE
  1190. span = timediff[maxloc] + timediff[maxloc+postzerocnt+1];
  1191. halfspan = span/2.0;
  1192. timediff[maxloc] = halfspan;
  1193. timediff[maxloc+postzerocnt+1] = halfspan;
  1194. } else { // Else, maximum entirely followed by zeros, span max seg and one BELOW
  1195. if(adjacent) { // if adjacent to others
  1196. maxloc -= adjacent; // Find earliest maxdiff segment
  1197. prezerocnt = adjacentzeros; // Find any zeros immediately prior to this
  1198. }
  1199. if(maxloc-prezerocnt-1 < 0) {
  1200. sprintf(errstr,"ERROR IN SEGMENT ACCOUNTING 3\n");
  1201. return(PROGRAM_ERROR);
  1202. }
  1203. span = timediff[maxloc] + timediff[maxloc-prezerocnt-1];
  1204. halfspan = span/2.0;
  1205. timediff[maxloc-prezerocnt-1] = halfspan;
  1206. timediff[maxloc] = halfspan;
  1207. }
  1208. }
  1209. }
  1210. if(unknotcnt % dz->iparam[KNOT_CLIP] == 0) { // Write out every Nth copy of unknotting, depending on value of KNOT_CLIP
  1211. writesteps++;
  1212. switch(passno) {
  1213. case(0):
  1214. outdatacnt += combopatterncnt;
  1215. break;
  1216. case(1):
  1217. if(respacecnt) {
  1218. for(n = 0; n < combopatterncnt;n++) {
  1219. outpos[n] = spatpos[n] + 1.0; // Reconvert current spatial-position of each event to (0)1-8 range for output channel
  1220. if(outpos[n] > 8.0)
  1221. outpos[n] -= 8.0;
  1222. }
  1223. for(r=0;r<dz->iparam[KNOT_UNKNOTREP];r++) { // Copy to output UNKNOTREP copies of part-unknotted stream
  1224. sum = 0.0;
  1225. outdata[outdatacnt++] = bastime;
  1226. outdata[outdatacnt++] = comboarray[1];
  1227. outdata[outdatacnt++] = comboarray[2];
  1228. outdata[outdatacnt++] = outpos[0]; // Put in new position data
  1229. m = 4;
  1230. for(n = 0; n < outdiffcnt; n++) {
  1231. sum += timediff[n]; // Increment time through the new pattern
  1232. outdata[outdatacnt++] = sum + bastime; // Offet time by start-time of this pattern
  1233. m++; // Copy the MIDI-level data to output
  1234. outdata[outdatacnt++] = comboarray[m++];
  1235. outdata[outdatacnt++] = comboarray[m++];
  1236. m++;
  1237. outdata[outdatacnt++] = outpos[n+1]; // Put in new position data
  1238. }
  1239. bastime += dz->celltime; // Increment to next pattern start time
  1240. }
  1241. for(n = 0; n < combopatterncnt;n++) {
  1242. spatpos[n] += spatstep[n]; // Advance position towards goal position for each pattern element
  1243. if(spatpos[n] >= 8.0) // spatpos uses 0 - <8 range for modulo8 arithmetic
  1244. spatpos[n] -= 8.0;
  1245. else if(spatpos[n] < 0.0)
  1246. spatpos[n] += 8.0;
  1247. }
  1248. } else {
  1249. for(r=0;r<dz->iparam[KNOT_UNKNOTREP];r++) { // Copy to output UNKNOTREP copies of part-unknotted stream
  1250. sum = 0.0;
  1251. outdata[outdatacnt++] = bastime;
  1252. outdata[outdatacnt++] = comboarray[1];
  1253. outdata[outdatacnt++] = comboarray[2];
  1254. outdata[outdatacnt++] = comboarray[3];
  1255. m = 4;
  1256. for(n = 0; n < outdiffcnt; n++) {
  1257. sum += timediff[n]; // Increment time through the new pattern
  1258. outdata[outdatacnt++] = sum + bastime; // Offet time by start-time of this pattern
  1259. m++; // Copy the MIDI-level-position data to output
  1260. outdata[outdatacnt++] = comboarray[m++];
  1261. outdata[outdatacnt++] = comboarray[m++];
  1262. outdata[outdatacnt++] = comboarray[m++];
  1263. }
  1264. bastime += dz->celltime; // Increment to next pattern start time
  1265. }
  1266. }
  1267. break;
  1268. }
  1269. }
  1270. unknotcnt++;
  1271. }
  1272. if(passno == 0) {
  1273. if(writesteps <= 1)
  1274. fprintf(stdout,"INFO: %d STEP ONLY: NO UNKNOTTING\n",writesteps);
  1275. else
  1276. fprintf(stdout,"INFO: %d STEPS IN UNKNOTTING\n",writesteps);
  1277. fflush(stdout);
  1278. if(dz->mode == KNOTCNT)
  1279. return FINISHED;
  1280. else if(writesteps <= 1) {
  1281. fprintf(stdout,"WARNING: NO UNKNOTTING - MIN or CLIP TOO LARGE?? - HENCE NO RESPATIALISING.\n");
  1282. fflush(stdout);
  1283. }
  1284. outdatacnt *= 4; // Every counted patterns needs 4 slots
  1285. outdatacnt *= dz->iparam[KNOT_UNKNOTREP]; // Each pattern is output KNOT_UNKNOTREP times
  1286. if((*out_data = (double *)malloc(outdatacnt * sizeof(double)))==NULL) {
  1287. sprintf(errstr,"Insufficient memory to store output data.\n");
  1288. return(MEMORY_ERROR);
  1289. }
  1290. outdata = *out_data;
  1291. if(spacetyp > 0 && !dz->vflag[3] && writesteps > 1) { // Respatialise DURING unknotting
  1292. respacecnt = writesteps;
  1293. setup_respatialisation_params(spatpos,spatstep,comboarray,combopatterncnt,respacecnt,dz);
  1294. }
  1295. }
  1296. }
  1297. if(dz->mode == DO_KNOT) {
  1298. unknotting_eventcnt = outdatacnt/4;
  1299. m = unknotting_eventcnt - 1;
  1300. n = 0;
  1301. outpatterncnt = writesteps * dz->iparam[KNOT_UNKNOTREP]; // Number of patterns in unknotting output
  1302. m = outpatterncnt - 1;
  1303. while(m > n) { // INVERT ARRAY in groups of patterns
  1304. tm = m * combopatterncnt * 4; // Indeces of time at start of each pattern
  1305. tn = n * combopatterncnt * 4;
  1306. for(k = 0; k < combopatterncnt;k++) { // Progressing through one entire pattern
  1307. tim_m = outdata[tm];
  1308. mid_m = outdata[tm+1];
  1309. lev_m = outdata[tm+2];
  1310. pos_m = outdata[tm+3];
  1311. tim_n = outdata[tn];
  1312. mid_n = outdata[tn+1];
  1313. lev_n = outdata[tn+2];
  1314. pos_n = outdata[tn+3];
  1315. outdata[tm] = tim_n; // Exchange data of the two patterns
  1316. outdata[tm+1] = mid_n;
  1317. outdata[tm+2] = lev_n;
  1318. outdata[tm+3] = pos_n;
  1319. outdata[tn] = tim_m;
  1320. outdata[tn+1] = mid_m;
  1321. outdata[tn+2] = lev_m;
  1322. outdata[tn+3] = pos_m;
  1323. tm += 4;
  1324. tn += 4;
  1325. }
  1326. m--;
  1327. n++;
  1328. }
  1329. bastime = 0.0;
  1330. tlast = 0;
  1331. outpatterncnt = writesteps * dz->iparam[KNOT_UNKNOTREP]; // Number of patterns in unknotting output
  1332. for(n = 0,r = 0; n < outpatterncnt;n++,r+=combopatterncnt) { // For every pattern, (each pattern starts at r)
  1333. sum = 0.0; // Single pattern timesum
  1334. tnow = r * 4; // Index in outpattern of start of this pattern
  1335. for(m=0,k=r;m<combopatterncnt-1;m++,k++) { // Move time-pattern to correct basetime
  1336. tnext = tnow+4;
  1337. span = outdata[tnext] - outdata[tnow];
  1338. outdata[tnow] = sum + bastime;
  1339. sum += span;
  1340. tnow = tnext;
  1341. }
  1342. outdata[tnow] = sum + bastime;
  1343. bastime += dz->celltime;
  1344. }
  1345. }
  1346. *knotdatacnt = outdatacnt;
  1347. return(FINISHED);
  1348. }
  1349. /********************************************* UNKNOT_OUTPUT *********************************/
  1350. int unknot_output(int *patterncnt,int knotdatacnt,double *spatpos,double *spatstep,double *comboarray,int combopatterncnt,double *outdata,dataptr dz)
  1351. {
  1352. int respace = 0, n, pcnt, r, ccnt, spacetyp = dz->iparam[KNOT_SPACETYP];
  1353. double *thispattern, *combo, bastime, endtime, thispos, starttime;
  1354. int combosize = 0, tim, mid, lev, pos, outpatterncnt, unknotting_eventcnt, sttim, stmid, stlev, stpos;
  1355. char temp[400];
  1356. for(n=0;n<dz->infilecnt;n++) {
  1357. for(pcnt=0;pcnt < patterncnt[n]; pcnt++)
  1358. combosize++;
  1359. }
  1360. combosize *= 4;
  1361. if((combo = (double *)malloc(combosize * sizeof(double)))==NULL) {
  1362. sprintf(errstr,"Insufficient memory to store intermediate combined-patterns.\n");
  1363. return(MEMORY_ERROR);
  1364. }
  1365. bastime = 0.0;
  1366. if(dz->mode == DO_UNKNOT) {
  1367. if(dz->iparam[KNOT_PATREP]) {
  1368. if(dz->vflag[2]) {
  1369. sprintf(temp,";ORIGINAL PATTERN REPEATS\n");
  1370. fputs(temp,dz->fp);
  1371. }
  1372. for(n=0;n<dz->infilecnt;n++) {
  1373. for(r = 0; r < dz->iparam[KNOT_PATREP];r++) {
  1374. thispattern = dz->parray[n];
  1375. tim = 0;
  1376. mid = 1;
  1377. lev = 2;
  1378. pos = 3;
  1379. for(pcnt=0;pcnt < patterncnt[n] - 1; pcnt++) { // Don't output the endmarker events
  1380. sprintf(temp,"%lf\t%d\t%lf\t%lf\n",thispattern[tim] + bastime,(int)round(thispattern[mid]),thispattern[lev],thispattern[pos]);
  1381. if(fputs(temp,dz->fp) < 0) {
  1382. sprintf(errstr,"FAILED TO WRITE TO INDIVIDUAL PATTERNS OUTPUT FILE \n");
  1383. return SYSTEM_ERROR;
  1384. }
  1385. tim += 4;
  1386. mid += 4;
  1387. lev += 4;
  1388. pos += 4;
  1389. }
  1390. if(dz->vflag[2]) {
  1391. sprintf(temp,"\n");
  1392. fputs(temp,dz->fp);
  1393. }
  1394. bastime += dz->celltime;
  1395. }
  1396. }
  1397. }
  1398. if(dz->iparam[KNOT_COMBOREP]) {
  1399. if(dz->vflag[2]) {
  1400. sprintf(temp,";REPEATS OF COMBINATIONS OF ORIGINAL PATTERNS\n");
  1401. fputs(temp,dz->fp);
  1402. }
  1403. for(ccnt = 0; ccnt < dz->itemcnt; ccnt++) { // For each pattern combination
  1404. combopatterncnt = GenerateKnotCombo(combo,ccnt,patterncnt,dz);
  1405. for(r=0;r<dz->iparam[KNOT_COMBOREP];r++) {
  1406. tim = 0;
  1407. mid = 1;
  1408. lev = 2;
  1409. pos = 3;
  1410. for(pcnt=0;pcnt < combopatterncnt; pcnt++) {
  1411. sprintf(temp,"%lf\t%d\t%lf\t%lf\n",combo[tim] + bastime,(int)round(combo[mid]),combo[lev],combo[pos]);
  1412. if(fputs(temp,dz->fp) < 0) {
  1413. sprintf(errstr,"FAILED TO WRITE PATTERN COMBINATIONS TO OUTPUT FILE \n");
  1414. return SYSTEM_ERROR;
  1415. }
  1416. tim += 4;
  1417. mid += 4;
  1418. lev += 4;
  1419. pos += 4;
  1420. }
  1421. if(dz->vflag[2]) {
  1422. sprintf(temp,"\n");
  1423. fputs(temp,dz->fp);
  1424. }
  1425. bastime += dz->celltime;
  1426. }
  1427. }
  1428. }
  1429. }
  1430. if(dz->iparam[KNOT_ALLREP]) { // For combination of all patterns
  1431. if(dz->vflag[2]) {
  1432. sprintf(temp,";REPEATS OF COMBINED-PATTERN\n");
  1433. fputs(temp,dz->fp);
  1434. }
  1435. combopatterncnt = GenerateKnotCombo(combo,-1,patterncnt,dz);
  1436. for(r=0;r<dz->iparam[KNOT_ALLREP];r++) {
  1437. tim = 0;
  1438. mid = 1;
  1439. lev = 2;
  1440. pos = 3;
  1441. for(pcnt=0;pcnt < combopatterncnt; pcnt++) {
  1442. if(dz->mode == DO_KNOT) // Get unknotted spatialisation
  1443. thispos = outdata[pos];
  1444. else
  1445. thispos = combo[pos];
  1446. sprintf(temp,"%lf\t%d\t%lf\t%lf\n",combo[tim] + bastime,(int)round(combo[mid]),combo[lev],thispos);
  1447. if(fputs(temp,dz->fp) < 0) {
  1448. sprintf(errstr,"FAILED TO WRITE TOTAL-PATTERN REPETITIONS TO OUTPUT FILE \n");
  1449. return SYSTEM_ERROR;
  1450. }
  1451. tim += 4;
  1452. mid += 4;
  1453. lev += 4;
  1454. pos += 4;
  1455. }
  1456. if(dz->vflag[2]) {
  1457. sprintf(temp,"\n");
  1458. fputs(temp,dz->fp);
  1459. }
  1460. bastime += dz->celltime;
  1461. }
  1462. if(dz->mode == DO_KNOT) { // Get unknotted spatialisation
  1463. for(n= 0;n < combopatterncnt; n++) {
  1464. pos = (n * 4) + 3;
  1465. thispos = outdata[pos];
  1466. }
  1467. }
  1468. }
  1469. // OUTPUT THE UNKNOTTING
  1470. unknotting_eventcnt = knotdatacnt/4;
  1471. outpatterncnt = unknotting_eventcnt/combopatterncnt;
  1472. tim = 0;
  1473. mid = 1;
  1474. lev = 2;
  1475. pos = 3;
  1476. endtime = bastime;
  1477. if(dz->vflag[2]) {
  1478. sprintf(temp,";UNKNOTTING\n");
  1479. fputs(temp,dz->fp);
  1480. }
  1481. for(n = 0; n < unknotting_eventcnt;n++) {
  1482. sprintf(temp,"%lf\t%d\t%lf\t%lf\n",outdata[tim] + bastime,(int)round(outdata[mid]),outdata[lev],outdata[pos]);
  1483. if(fputs(temp,dz->fp) < 0) {
  1484. sprintf(errstr,"FAILED TO WRITE UNKNOTTING DATA TO OUTPUT FILE \n");
  1485. return SYSTEM_ERROR;
  1486. }
  1487. if(dz->vflag[2]) {
  1488. if(n % combopatterncnt == combopatterncnt-1) {
  1489. sprintf(temp,"\n");
  1490. fputs(temp,dz->fp);
  1491. }
  1492. }
  1493. tim += 4;
  1494. mid += 4; // Note that tim advances to end of unknotting array "outdata"
  1495. lev += 4;
  1496. pos += 4;
  1497. }
  1498. bastime += (dz->celltime * outpatterncnt); // Next event is outpatterncnt cells later
  1499. // IF repatialise AFTER unknotting CALCULATE RESPATIALISATION PARAMS
  1500. if(spacetyp > 0 && dz->vflag[3] && dz->iparam[KNOT_GOALREP] > 1) {
  1501. respace = 1;
  1502. setup_respatialisation_params(spatpos,spatstep,comboarray,combopatterncnt,dz->iparam[KNOT_GOALREP],dz);
  1503. }
  1504. // OUTPUT THE GOAL PATTERN
  1505. if(dz->iparam[KNOT_GOALREP]) {
  1506. if(dz->vflag[2]) {
  1507. sprintf(temp,";GOAL PATTERN REPEATS\n");
  1508. fputs(temp,dz->fp);
  1509. }
  1510. combopatterncnt = 0;
  1511. for(n=0;n < dz->infilecnt;n++)
  1512. combopatterncnt += patterncnt[n] - 1; // Count total number of events in combined pattern
  1513. sttim = tim - (combopatterncnt * 4); // Set counters to start of goal pattern (in unknotting array)
  1514. stmid = mid - (combopatterncnt * 4);
  1515. stlev = lev - (combopatterncnt * 4);
  1516. stpos = pos - (combopatterncnt * 4);
  1517. starttime = outdata[sttim];
  1518. tim = sttim;
  1519. mid = stmid;
  1520. lev = stlev;
  1521. pos = stpos;
  1522. for(r=0;r<dz->iparam[KNOT_GOALREP];r++) {
  1523. for(n = 0; n < combopatterncnt;n++) {
  1524. if(respace) {
  1525. thispos = spatpos[n] + 1.0; // Reconvert to (0)1-8 range for output channel
  1526. if(thispos > 8.0)
  1527. thispos -= 8.0;
  1528. sprintf(temp,"%lf\t%d\t%lf\t%lf\n",(outdata[tim] - starttime) + bastime,(int)round(outdata[mid]),outdata[lev],thispos);
  1529. if(fputs(temp,dz->fp) < 0) {
  1530. sprintf(errstr,"FAILED TO WRITE GOAL EVENT REPETITIONS TO OUTPUT FILE\n");
  1531. return SYSTEM_ERROR;
  1532. }
  1533. spatpos[n] += spatstep[n]; // Advance position towards goal position for each pattern element
  1534. if(spatpos[n] >= 8.0) // spatpos uses 0 - <8 range for modulo8 arithmetic
  1535. spatpos[n] -= 8.0;
  1536. else if(spatpos[n] < 0.0)
  1537. spatpos[n] += 8.0;
  1538. } else {
  1539. sprintf(temp,"%lf\t%d\t%lf\t%lf\n",(outdata[tim] - starttime) + bastime,(int)round(outdata[mid]),outdata[lev],outdata[pos]);
  1540. if(fputs(temp,dz->fp) < 0) {
  1541. sprintf(errstr,"FAILED TO WRITE GOAL EVENT REPETITIONS TO OUTPUT FILE\n");
  1542. return SYSTEM_ERROR;
  1543. }
  1544. }
  1545. tim += 4;
  1546. mid += 4;
  1547. lev += 4;
  1548. pos += 4;
  1549. }
  1550. tim = sttim; // back to start of last pattern of unknotting's "outdata"
  1551. mid = stmid;
  1552. lev = stlev;
  1553. pos = stpos;
  1554. if(dz->vflag[2]) {
  1555. sprintf(temp,"\n");
  1556. fputs(temp,dz->fp);
  1557. }
  1558. bastime += dz->celltime;
  1559. }
  1560. }
  1561. if(dz->mode == DO_KNOT) {
  1562. if(dz->iparam[KNOT_COMBOREP]) {
  1563. if(dz->vflag[2]) {
  1564. sprintf(temp,";REPEATS OF COMBINATIONS OF ORIGINAL PATTERNS\n");
  1565. fputs(temp,dz->fp);
  1566. }
  1567. for(ccnt = 0; ccnt < dz->itemcnt; ccnt++) { // For each pattern combination
  1568. combopatterncnt = GenerateKnotCombo(combo,ccnt,patterncnt,dz);
  1569. for(r=0;r<dz->iparam[KNOT_COMBOREP];r++) {
  1570. tim = 0;
  1571. mid = 1;
  1572. lev = 2;
  1573. pos = 3;
  1574. for(pcnt=0;pcnt < combopatterncnt; pcnt++) {
  1575. sprintf(temp,"%lf\t%d\t%lf\t%lf\n",combo[tim] + bastime,(int)round(combo[mid]),combo[lev],combo[pos]);
  1576. if(fputs(temp,dz->fp) < 0) {
  1577. sprintf(errstr,"FAILED TO WRITE PATTERN COMBINATIONS TO OUTPUT FILE \n");
  1578. return SYSTEM_ERROR;
  1579. }
  1580. tim += 4;
  1581. mid += 4;
  1582. lev += 4;
  1583. pos += 4;
  1584. }
  1585. if(dz->vflag[2]) {
  1586. sprintf(temp,"bastime = %lf\n",bastime);
  1587. fputs(temp,dz->fp);
  1588. }
  1589. bastime += dz->celltime;
  1590. }
  1591. }
  1592. }
  1593. if(dz->iparam[KNOT_PATREP]) {
  1594. if(dz->vflag[2]) {
  1595. sprintf(temp,";ORIGINAL PATTERN REPEATS\n");
  1596. fputs(temp,dz->fp);
  1597. }
  1598. for(n=0;n<dz->infilecnt;n++) {
  1599. for(r = 0; r < dz->iparam[KNOT_PATREP];r++) {
  1600. thispattern = dz->parray[n];
  1601. tim = 0;
  1602. mid = 1;
  1603. lev = 2;
  1604. pos = 3;
  1605. for(pcnt=0;pcnt < patterncnt[n] - 1; pcnt++) { // Don't output the endmarker events
  1606. sprintf(temp,"%lf\t%d\t%lf\t%lf\n",thispattern[tim] + bastime,(int)round(thispattern[mid]),thispattern[lev],thispattern[pos]);
  1607. if(fputs(temp,dz->fp) < 0) {
  1608. sprintf(errstr,"FAILED TO WRITE TO INDIVIDUAL PATTERNS OUTPUT FILE \n");
  1609. return SYSTEM_ERROR;
  1610. }
  1611. tim += 4;
  1612. mid += 4;
  1613. lev += 4;
  1614. pos += 4;
  1615. }
  1616. if(dz->vflag[2]) {
  1617. sprintf(temp,"\n");
  1618. fputs(temp,dz->fp);
  1619. }
  1620. bastime += dz->celltime;
  1621. }
  1622. }
  1623. }
  1624. }
  1625. return FINISHED;
  1626. }
  1627. /**************************************** PULSE_REGULAR ****************************************/
  1628. int pulse_regular(double a,double b,double minstep)
  1629. {
  1630. if(fabs(a-b) < minstep)
  1631. return 1;
  1632. return 0;
  1633. }
  1634. /**************************************** PULSE_MORE ****************************************/
  1635. int pulse_more(double thisstep,double maxstep,double minerror)
  1636. {
  1637. if(thisstep > maxstep + minerror)
  1638. return 1;
  1639. return 0;
  1640. }
  1641. /**************************************** GENERATEKNOTCOMBO ****************************************/
  1642. // dz->iparray[dz->itemcnt] contains the sizes of each combo
  1643. // dz->iparray[0] to dz->iparray[itemcnt-1] contains the actual combo
  1644. int GenerateKnotCombo (double *comboarray,int combono,int *patterncnt,dataptr dz)
  1645. {
  1646. int arraysize = 0;
  1647. int *thiscombo, *combocnts, thiscombocnt, k = 0, n, m, thispattern;
  1648. if(combono >= 0) {
  1649. thiscombo = dz->iparray[combono]; // Array with list of patterns in this combination
  1650. combocnts = dz->iparray[dz->itemcnt]; // Array counting number of members in EACH combination
  1651. thiscombocnt = combocnts[combono]; // Count of members in THIS combination
  1652. for(n = 0;n < thiscombocnt;n++) { // For every pattern in this combination
  1653. thispattern = thiscombo[n]; // Get this pattern
  1654. thispattern--; // Change to 0 to n-1 counting
  1655. for(m=0;m < (patterncnt[thispattern] - 1) * 4; m++) {
  1656. comboarray[k++] = dz->parray[thispattern][m];
  1657. arraysize++;
  1658. }
  1659. }
  1660. } else {
  1661. for(n=0;n < dz->infilecnt;n++) { // Copy all patterns into combination array
  1662. for(m=0;m < (patterncnt[n] - 1) * 4; m++) {
  1663. comboarray[k++] = dz->parray[n][m];
  1664. arraysize++;
  1665. }
  1666. }
  1667. }
  1668. thiscombocnt = arraysize/4;
  1669. sortcomoboarray(thiscombocnt,comboarray);
  1670. return thiscombocnt;
  1671. }
  1672. /**************************************** SORTCOMOBOARRAY ****************************************/
  1673. void sortcomoboarray(int combopatterncnt,double *comboarray)
  1674. {
  1675. int n, m, tn, tm;
  1676. double tim_m, mid_m,lev_m, pos_m, tim_n, mid_n, lev_n, pos_n;
  1677. for(n=0;n < combopatterncnt - 1;n++) { // Sort combined pattern into time-order
  1678. tn = n * 4;
  1679. tim_n = comboarray[tn];
  1680. for(m=n+1;m < combopatterncnt;m++) {
  1681. tm = m * 4;
  1682. tim_m = comboarray[tm];
  1683. if(tim_m < tim_n) {
  1684. mid_n = comboarray[tn+1];
  1685. lev_n = comboarray[tn+2];
  1686. pos_n = comboarray[tn+3];
  1687. mid_m = comboarray[tm+1];
  1688. lev_m = comboarray[tm+2];
  1689. pos_m = comboarray[tm+3];
  1690. comboarray[tn] = tim_m;
  1691. comboarray[tn+1] = mid_m;
  1692. comboarray[tn+2] = lev_m;
  1693. comboarray[tn+3] = pos_m;
  1694. comboarray[tm] = tim_n;
  1695. comboarray[tm+1] = mid_n;
  1696. comboarray[tm+2] = lev_n;
  1697. comboarray[tm+3] = pos_n;
  1698. tim_n = tim_m;
  1699. }
  1700. }
  1701. }
  1702. }
  1703. /**************************************** SETUP_RESPATIALISATION_PARAMS ****************************************/
  1704. int setup_respatialisation_params(double *spatpos,double *spatstep,double *comboarray, int combopatterncnt,int respacecnt,dataptr dz)
  1705. {
  1706. int n, m, spactyp;
  1707. int steps, pos;
  1708. double final_spatial_spread = 0, final_space_step, startpos, distance, goal;
  1709. spactyp = dz->iparam[KNOT_SPACETYP];
  1710. if(spactyp == 1) {
  1711. for(n=0,m=1;n<combopatterncnt;n+=2,m+=2) { // Assign actual goal-spatial-positions to each event
  1712. spatpos[n] = dz->param[KNOT_CHANA]; // Alternating
  1713. spatpos[m] = dz->param[KNOT_CHANB];
  1714. }
  1715. } else {
  1716. switch(spactyp) { // Assign final spatial spread for each event
  1717. case(2):
  1718. case(4):
  1719. if(dz->param[KNOT_CHANB] > dz->param[KNOT_CHANA])
  1720. final_spatial_spread = dz->param[KNOT_CHANB] - dz->param[KNOT_CHANA];
  1721. else if (dz->param[KNOT_CHANB] == dz->param[KNOT_CHANA])
  1722. final_spatial_spread = 8;
  1723. else // dz->param[KNOT_CHANB] < dz->param[KNOT_CHANA])
  1724. final_spatial_spread = dz->param[KNOT_CHANB] - dz->param[KNOT_CHANA] + 8;
  1725. break;
  1726. case(3):
  1727. case(5):
  1728. if(dz->param[KNOT_CHANA] > dz->param[KNOT_CHANB])
  1729. final_spatial_spread = dz->param[KNOT_CHANA] - dz->param[KNOT_CHANB];
  1730. else if (dz->param[KNOT_CHANA] == dz->param[KNOT_CHANB])
  1731. final_spatial_spread = 8;
  1732. else // dz->param[KNOT_CHANA] < dz->param[KNOT_CHANB])
  1733. final_spatial_spread = dz->param[KNOT_CHANA] - dz->param[KNOT_CHANB] + 8;
  1734. break;
  1735. }
  1736. switch(spactyp) { // Assign actual goal-spatial-positions for each event
  1737. case(2):
  1738. final_space_step = (double)final_spatial_spread/(double)(combopatterncnt-1);
  1739. spatpos[0] = dz->param[KNOT_CHANA];
  1740. for(n=1;n<combopatterncnt-1;n++) {
  1741. spatpos[n] = dz->param[KNOT_CHANA] + (n * final_space_step);
  1742. if(spatpos[n] >= 8.0)
  1743. spatpos[n] -= 8.0;
  1744. }
  1745. spatpos[combopatterncnt-1] = dz->param[KNOT_CHANB];
  1746. break;
  1747. case(3):
  1748. final_space_step = (double)final_spatial_spread/(double)(combopatterncnt-1);
  1749. spatpos[0] = dz->param[KNOT_CHANA];
  1750. for(n=1;n<combopatterncnt-1;n++) {
  1751. spatpos[n] = dz->param[KNOT_CHANA] - (n * final_space_step);
  1752. if(spatpos[n] < 0.0)
  1753. spatpos[n] += 8.0;
  1754. }
  1755. spatpos[combopatterncnt-1] = dz->param[KNOT_CHANB];
  1756. break;
  1757. case(4):
  1758. steps = combopatterncnt/2;
  1759. if(steps * 2 != combopatterncnt)
  1760. steps++;
  1761. final_space_step = (double)final_spatial_spread/(double)steps;
  1762. spatpos[0] = dz->param[KNOT_CHANA];
  1763. for(n=1;n<steps;n++) {
  1764. spatpos[n] = dz->param[KNOT_CHANA] + (n * final_space_step);
  1765. if(spatpos[n] >= 8.0)
  1766. spatpos[n] -= 8.0;
  1767. }
  1768. spatpos[n++] = dz->param[KNOT_CHANB];
  1769. for(m = 1;n<combopatterncnt;n++,m++) {
  1770. spatpos[n] = dz->param[KNOT_CHANB] - (m * final_space_step);
  1771. if(spatpos[n] < 0.0)
  1772. spatpos[n] += 8.0;
  1773. }
  1774. break;
  1775. case(5):
  1776. steps = combopatterncnt/2;
  1777. if(steps * 2 != combopatterncnt)
  1778. steps++;
  1779. final_space_step = (double)final_spatial_spread/(double)steps;
  1780. spatpos[0] = dz->param[KNOT_CHANA];
  1781. for(n=1;n<steps;n++) {
  1782. spatpos[n] = dz->param[KNOT_CHANA] - (n * final_space_step);
  1783. if(spatpos[n] < 0.0)
  1784. spatpos[n] += 8.0;
  1785. }
  1786. spatpos[n++] = dz->param[KNOT_CHANB];
  1787. for(m = 1;n<combopatterncnt;n++,m++) {
  1788. spatpos[n] = dz->param[KNOT_CHANB] + (m * final_space_step);
  1789. if(spatpos[n] >= 8.0)
  1790. spatpos[n] -= 8.0;
  1791. }
  1792. break;
  1793. }
  1794. } // Calculate stepsize necessary to move events to final positions by shortest route
  1795. pos = 3;
  1796. for(n=0;n<combopatterncnt;n++) { // Each event takes shortest route to final position
  1797. startpos = comboarray[pos] - 1; // e.g. 7:0 7:4 0:7 4:7
  1798. distance = fabs(spatpos[n] - startpos); // e.g. 7 3 7 3
  1799. distance = min(distance,8.0 - distance); // e.g. 1 3 1 3
  1800. if((goal = startpos + distance) >= 8.0) // e.g. 8 10 1 7
  1801. goal -= 8.0; // e.g. 0 2 1 7
  1802. if(flteq(goal,spatpos[n])) // YES NO NO YES
  1803. spatstep[n] = distance/(respacecnt-1); // clock clock
  1804. else // anticlok anticlok
  1805. spatstep[n] = -distance/(respacecnt-1);
  1806. spatpos[n] = comboarray[pos] - 1; // Assign the initial spatial positions of each event (in 0 to chas-1 frame)
  1807. pos += 4;
  1808. }
  1809. return FINISHED;
  1810. }
  1811. int IsAnIntegerInRange(char *str,int imin, int imax)
  1812. {
  1813. char *q, *p = str;
  1814. int i;
  1815. q = p + strlen(str);
  1816. q--;
  1817. while(q != p) {
  1818. if(!isdigit(*q))
  1819. return 0;
  1820. q--;
  1821. }
  1822. i = atoi(str);
  1823. if(i < imin || i > imax)
  1824. return 0;
  1825. return 1;
  1826. }
  1827. int IsAFilename(char *str)
  1828. {
  1829. char *q, *p = str;
  1830. int ispoint = 0, alpha = 0, wasbackslash = 0;
  1831. if(isdigit(*p) || (*p == '.') || (*p == '-'))
  1832. return 0;
  1833. q = p + strlen(str);
  1834. q--;
  1835. while(q != p) {
  1836. if(!isalnum(*q) && (*q != '-') && (*q != '_') && (*q != '.') && (*q != '\\'))
  1837. return 0; // Must be aphanumeric with valid spearators
  1838. if(isalpha(*q))
  1839. alpha++;
  1840. if(*q == '\\') { // RWD removed extra brackets
  1841. if(wasbackslash)
  1842. return 0; // No double backslashes
  1843. wasbackslash = 1;
  1844. } else
  1845. wasbackslash = 0;
  1846. if(*q == '.') {
  1847. if(ispoint)
  1848. return 0; // No more than one file-extension-marker "."
  1849. ispoint++;
  1850. }
  1851. q--;
  1852. }
  1853. if(!alpha) // Must have alphabetic chars
  1854. return 0;
  1855. return 1;
  1856. }