gramophone-0.8.13a/0000755000175000017500000000000011004322136014301 5ustar giovannigiovannigramophone-0.8.13a/AUTHORS0000644000175000017500000000006710757737531015403 0ustar giovannigiovanniGiovanni Ferranti gramophone-0.8.13a/COPYING0000644000175000017500000004307010757737531015367 0ustar giovannigiovanni GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. gramophone-0.8.13a/ChangeLOG0000644000175000017500000000664311004322004015756 0ustar giovannigiovanni/* * $Id: ChangeLog,v 0.8.13a 2008-04-25 10:08:09 gyo Exp $ */ /* Use this format for the entry headers: YYYY-MM-DD HH:MM UTC[-|+]hhmm Your Full Name For example: 2002-12-01 23:12 UTC+0100 Foo Bar (use some sort of indicator for @ to avoid spamming) Legend: ! fixes + addition - removal % optimization * modification that are not changing functionality */ 2008-04-25 10:08 UTC+0100 Giovanni Ferranti (giovanni_at_giovanniferranti_dot_it) !grammyVM.c Fixed bug in midi generation 2008-02-21 14:57 UTC+0100 Giovanni Ferranti (giovanni_at_giovanniferranti_dot_it) !grammyVM.c !GRAMophone.y Fixed bug in operator precedence and equation calculus !grammyVM.c Fixed another bug in cycles of Chomsky productions 2008-02-16 08:00 UTC+0100 Giovanni Ferranti (giovanni_at_giovanniferranti_dot_it) +GRAMophone.l +GRAMophone.y +global.h +grammyVM.c +hash.c +errors.c Added "else" in conditional productions !grammyVM.c Fixed bug in cycles of Chomsky productions 2008-02-08 19:02 UTC+0100 Giovanni Ferranti (giovanni_at_giovanniferranti_dot_it) !grammyVM.c Fixed bug in conditional Chomsky productions 2008-01-21 18:24 UTC+0100 Giovanni Ferranti (giovanni_at_giovanniferranti_dot_it) +GRAMophone.l +GRAMophone.y +global.h +grammyVM.c +init.c +errors.c Added the print() function 2007-11-30 18:24 UTC+0100 Giovanni Ferranti (giovanni_at_giovanniferranti_dot_it) !grammyVM.c Fixed bug in calculus of Inversion of Retrograde 2007-08-23 19:47 UTC+0100 Giovanni Ferranti (giovanni_at_giovanniferranti_dot_it) *gramophone2.1 Fixed charset problems +Makefile more Debian compliant 2007-08-23 06:12 UTC+0100 Giovanni Ferranti (giovanni_at_giovanniferranti_dot_it) +GRAMophone.y +global.h +grammyVM.c Added the melodic operator retrograde() !grammyVM.c Fixed bug in calculus of nested melodic operators +gramophone2.1 Added Unix Man Pages +Makefile.win32 Added specific Makefile for Windows 2007-06-15 11:09 UTC+0100 Giovanni Ferranti (giovanni_at_giovanniferranti_dot_it) +GRAMophone.l +GRAMophone.y +global.h +grammyVM.c +errors.c Added the "silent note" N[,,,] for variable update Added the update_var[] operator for variable update 2007-06-02 06:32 UTC+0100 Giovanni Ferranti (giovanni_at_giovanniferranti_dot_it) +GRAMophone.l +GRAMophone.y +global.h +grammyVM.c Added the module operator 'mod' !GRAMophone.c fixed the copyright notice 2007-05-30 06:13 UTC+0100 Giovanni Ferranti (giovanni_at_giovanniferranti_dot_it) !grammyVM.c Fixed the 'ghost rest' bug! :) 2007-05-29 07:33 UTC+0100 Giovanni Ferranti (giovanni_at_giovanniferranti_dot_it) !grammyVM.c Argh! Fixed a stupid bug introduced after last fix. I have been able to notice it only now, sorry! 2007-05-13 06:03 UTC+0100 Giovanni Ferranti (giovanni_at_giovanniferranti_dot_it) !grammyVM.c fixed a bug in melodic operators calculus 2007-05-12 07:59 UTC+0100 Giovanni Ferranti (giovanni_at_giovanniferranti_dot_it) !grammyVM.c initialized the stop variable to zero *Makefile added CFLAGS to work with GNU/Linux and Win32 code restyiling +Added binaries for GNU/Linux x86 and Win32 2007-05-08 19:02 UTC+0100 Giovanni Ferranti (giovanni_at_giovanniferranti_dot_it) !init.c initialized the default duration value to global resolution value 2007-05-07 17:51 UTC+0100 Giovanni Ferranti (giovanni_at_giovanniferranti_dot_it) + GRAMophone II first alpha release gramophone-0.8.13a/DOCS0000644000175000017500000000016510757737531015005 0ustar giovannigiovannion Unix systems, type man gramophone2 A pdf version of the manual is available at http://gramophone2.sourceforge.net/gramophone-0.8.13a/FAQ0000644000175000017500000000043610757737531014665 0ustar giovannigiovanniQ: GRAMophone II crashes during Chomsky generation! A: Probably you've set too many iterations. Chomsky generation makes heavy use of recursion, so can happen a stack overflow. On GNU/Linux systems you can avoid this problem with bash built-in command ulimit -s to increase stack size. gramophone-0.8.13a/GRAMophone.c0000644000175000017500000000773210757737531016444 0ustar giovannigiovanni/* * GRAMophone II, a grammar based algorithmic musical composition tool * -------------------------------------------------------------------- * * GRAMophone.c * * Copyright (c) 2007, Giovanni Ferranti * * GRAMophone II is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * -------------------------------------------------------------------- */ #include "global.h" void version() { printf("\n---------------------------------------------------------\n"); printf("GRAMophone II %s\n", VERSION); printf("(c) 2007 Giovanni Ferranti \n"); printf("This program is released under GNU General Public License\n\n"); printf("powered by Tim Thompson Midifile Library\n"); printf("---------------------------------------------------------\n\n"); } void dedicated() { printf(" _qp, ---- \n"); printf("\\ --- x0MM00&_ - \n"); printf(" -- QQM00 ~00 -- \n"); printf(" _##MO&b/\\$B& _ _ _,age\n"); printf("\\;y;p\\ymwm*xm01&NM#M&$d~Bm00&\"L$:&&&&TK&w )MQSVQ&7\n"); printf("0MMMg&&rrrrrMr.@000## \\shNM#P {aW$700009DL]#D2EQM*\n"); printf("OM&140M/gt&/ R*#000#w_!4p00 ^z,-w&#N&}MQL\"QFFfQW4\n"); printf("M1#kZp$6MMr~ ]N00MEM0N00#T G400M&& 0#\" N1 E##g\n"); printf("00M&QMM~~ M#0At#M0NMNN N6KRMMr&DD B0~:0Q&\n"); printf("d#&O\" JQMM1B0N0BM! \\$~32$:M0T J&&,W8W\n"); printf("TwF ,gpK BM#QDMM&^ m,hh$4Z$MMp 0p^$N0\n"); printf("O#N ~^Qq B \" 6NZ:4mMm&A8 BA&lMX\n"); printf("NNEb `\\ =-*a\\ Q2#p$B$d#N#*6 j##R00\n"); printf("#&, 3 bF&B0UQW0KMMg0p0ND&NN\n"); printf("B~ ( m #8SB�&&A@&#RQAKH]m\n"); printf("0Tt \\a, )@ {Kb#EB00x - Q*&00$#\n"); printf("#\\ / :##x -qp#pQmpgpq,_4@4r0BQ~_z3Q0M@MM0&\n"); printf("B: /\\ ~_\\MMB d#&h0#00#k0pEK&Mg& 1\\4NMM0M00Lp\n"); printf("#^ , ##_!W^jN ]k7@D#NZ_ `~ -m,jRMMM00M5\n"); printf("NWq ,Dp0000M0^ j#QMN0R6EBBg#B*M0M#QMg#BM0W\n"); printf("N#r \\ O6jM00MF` 0BMMNN0V9B@@&$ ~0MN10NMMMN&\n"); printf("R0xm - _pphgg__,#MM00NBMV9$~ xMM0#KM0BM#0\n"); printf("&&00mj - ,*N&0M0#&M0#K&1NM#0&& QM0NNMMM0&NM\n"); printf("~/~\\L?i`w ET&0QNBM0KX0#&N&B@ ,jp&B0$FM#0#0#\n"); printf("I want to dedicate GRAMophone II to Maria Fra'\n"); exit(0); } int main(int argc, char **argv) { extern FILE *yyin; checkOption=debugOption=0; strcpy(namefile, ""); ++argv; if(argc>1) { if(!strcmp(argv[0], "-c")) checkOption++; if(!strcmp(argv[0], "-d")) debugOption++; if(!strcmp(argv[0], "-dedicated")) dedicated(); if(checkOption||debugOption) { yyin=fopen(argv[1], "r"); if(argv[2]) strcpy(namefile, argv[2]); } else { yyin=fopen(argv[0], "r"); if(argv[1]) strcpy(namefile, argv[1]); } if(!yyin) { fprintf(stderr, "Error loading composition source!\n"); exit(1); } } else usageError(); version(); if(checkOption) printf("checking your composition source...\n"); initGRAMophone(); yyparse(); fclose(yyin); //print_expression_memory_map(); checkOption?(printf("the composition source is ok\n")):(grammyvm()); if(!checkOption) fclose(midi); return 0; } gramophone-0.8.13a/GRAMophone.l0000644000175000017500000001566010757737531016454 0ustar giovannigiovanni/* * GRAMophone II, a grammar based algorithmic musical composition tool * -------------------------------------------------------------------- * * Lex/Flex definitions * * Copyright (c) 2007, Giovanni Ferranti * * GRAMophone II is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * -------------------------------------------------------------------- */ D [0-9] L [a-z_] %{ #include #include "GRAMophone.tab.h" #define MAX_INCLUDE_DEPTH 64 YY_BUFFER_STATE strbuf, include_stack[MAX_INCLUDE_DEPTH]; unsigned char include_stack_ptr=1; extern char string_buf[]; char *string_buf_ptr; unsigned int countStr; unsigned int row=1; void count(); %} %x comment comment2 string incl %% "/*" BEGIN(comment); [^*\n]* "*"+[^/\n]* \n {++row;} <> sntx_err(EOF, ""); "*"+"/" BEGIN(INITIAL); "//" BEGIN(comment2); [^\n]* <> sntx_err(EOF, ""); \n { ++row; BEGIN(INITIAL); } "discography" {BEGIN(incl);} [ \t\v\n\f\r]* [^ \t\n]+ { if(include_stack_ptr>=MAX_INCLUDE_DEPTH) sntx_err(TOO_DEEPLY, ""); include_stack[include_stack_ptr++]=YY_CURRENT_BUFFER; yyin=fopen(yytext, "r"); if(!yyin) sntx_err(DISCOGRAPHY_NOT_FOUND, ""); yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); BEGIN(INITIAL); } <> { if(--include_stack_ptr<1) yyterminate(); else { yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(include_stack[include_stack_ptr]); } } "+" {return(PLUS);} "-" {return(MINUS);} "*" {return(MULT);} "/" {return(DIVIDE);} "mod" {return(MODULE);} "++" {return(PLUSPLUS);} "--" {return(MINMIN);} "==" {return(EQ);} "!=" {return(NE);} "<" {return(LT);} "<=" {return(LE);} ">" {return(GT);} ">=" {return(GE);} "||" {return(OR);} "&&" {return(AND);} "|" {return(NONDET);} "=" {return(ASSIGN);} "->" {return(PROD);} "?" {return(COND);} ":" {return(ELSE);} "!" {return(NOT);} "{" {return('{');} "}" {return('}');} "[" {return('[');} "]" {return(']');} "(" {return('(');} ")" {return(')');} "," {return(',');} ";" {return(';');} "%" {return('%');} "^" {return(CHORD);} "<<" {return(CNTX_PREV);} ">>" {return(CNTX_SUCC);} "step" {return(STEP);} "define" {return(DEFINE);} "composition" {return(COMPOSITION);} "of" {return(OF);} "author" {return(AUTHOR);} "grammar" {return(GRAMMAR);} "tempo" {return(TEMPO);} "resolution" {return(RESOLUTION);} "iterations" {return(ITERATIONS);} "time_signature" {return(TIME_SIGNATURE);} "velocity" {return(VELOCITY);} "release" {return(RELEASE);} "duration" {return(DURATION);} "player" {return(PLAYER);} "instrument" {return(INSTRUMENT);} "axiom" {return(AXIOM);} "@composition" {return(AT_COMPOSITION);} "chomsky" { yylval=1; return(CHOMSKY); } "lindenmayer" { yylval=2; return(LINDENMAYER); } "transpose" {return(TRANSPOSE);} "inversion" {return(INVERSION);} "retrograde" {return(RETROGRADE);} "retrograde_inv" {return(RETROGRADE_INV);} "repeat" {return(REPEAT);} "octave" {return(OCTAVE);} "channel" {return(CHANNEL);} "rand" {return(RAND);} "update_var" {return(UPDATE);} "msb" {return(MSB);} "print" {return(PRINT);} "A" { yylval=9; return(NOTE); } "A#" { yylval=10; return(NOTE); } "Ab" { yylval=8; return(NOTE); } "B" { yylval=11; return(NOTE); } "B#" { yylval=0; return(NOTE); } "Bb" { yylval=10; return(NOTE); } "C" { yylval=0; return(NOTE); } "C#" { yylval=1; return(NOTE); } "Cb" { yylval=11; return(NOTE); } "D" { yylval=2; return(NOTE); } "D#" { yylval=3; return(NOTE); } "Db" { yylval=1; return(NOTE); } "E" { yylval=4; return(NOTE); } "E#" { yylval=5; return(NOTE); } "Eb" { yylval=3; return(NOTE); } "F" { yylval=5; return(NOTE); } "F#" { yylval=6; return(NOTE); } "Fb" { yylval=4; return(NOTE); } "G" { yylval=7; return(NOTE); } "G#" { yylval=8; return(NOTE); } "Gb" { yylval=6; return(NOTE); } "R" { return(REST); } "N" { yylval=-1; return(NOTE); } {L}({L}|{D}|_)* { if(strlen(yytext)>VAR_LENGTH) sntx_err(TOO_LONG, "variable identifier "); if(check_id()==MACRO) { strbuf=YY_CURRENT_BUFFER; yy_switch_to_buffer( yy_scan_buffer((char *) dhSearch2(yytext), YY_BUF_SIZE)); } else return(IDENTIFIER); } [\0] { yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(strbuf); } {D}+ { yylval=atoi(yytext); return(NUMBER); } "@"{L}({L}|{D}|_)* {return(NON_TERMINAL);} \" { string_buf_ptr=string_buf; countStr=0; BEGIN(string); } \" { BEGIN(INITIAL); *string_buf_ptr='\0'; if(countStr>MAX_STR) sntx_err(TOO_LONG, "string "); return(STRING); } \n sntx_err(UNTERMINATED_STR, ""); \\n { ++countStr; *string_buf_ptr++='\n'; } \\t { ++countStr; *string_buf_ptr++='\t'; } \\r { ++countStr; *string_buf_ptr++='\r'; } \\b { ++countStr; *string_buf_ptr++='\b'; } \\f { ++countStr; *string_buf_ptr++='\f'; } \\(.|\n) { ++countStr; *string_buf_ptr++=yytext[1]; } [^\\\n\"]+ { char *yptr=yytext; while(*yptr) { ++countStr; *string_buf_ptr++=*yptr++; } } "\n" {++row;} [ \t\v\f\n] . { /* ignore bad characters */ } %% #ifndef yywrap yywrap() { return(1); } #endif int check_id() { if(dhSearch2(yytext)!='\0') return MACRO; else return IDENTIFIER; } gramophone-0.8.13a/GRAMophone.y0000644000175000017500000011425410757737531016470 0ustar giovannigiovanni/* * GRAMophone II, a grammar based algorithmic musical composition tool * ------------------------------------------------------------------- * * Yacc/Bison Grammar * * Copyright (c) 2007, Giovanni Ferranti * * GRAMophone II is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ------------------------------------------------------------------- */ %token DEFINE COMPOSITION OF AUTHOR GRAMMAR %token TEMPO RESOLUTION ITERATIONS CNTX_PREV CNTX_SUCC %token TIME_SIGNATURE VELOCITY PLAYER INSTRUMENT AXIOM %token CHOMSKY LINDENMAYER TRANSPOSE INVERSION RETROGRADE %token RETROGRADE_INV OCTAVE CHANNEL REPEAT MSB %token DURATION RELEASE AT_COMPOSITION STEP RAND UPDATE %token NOTE REST DEFNOTE DEFREST IDENTIFIER NUMBER MACRO %token NON_TERMINAL STRING NONDET CHORD PRINT %token PLUS MINUS MULT DIVIDE MODULE EQ NE LT LE GT GE AND OR NOT ASSIGN PROD COND ELSE %token PLUSPLUS MINMIN %{ #include "global.h" #include "lex.yy.c" extern unsigned int global_resolution, global_iterations, global_params[]; extern unsigned char grammarOption, probType, glob_num, glob_den, isGlobal; extern char *yytext, string_buf[], idTemp[]; extern char *title, *copyright; extern unsigned int tempo; unsigned char isDef=0; int ctrl[NUM_CTRL], ctrlTemp[MAX_RECURSION]; unsigned int ec, cc, ccCond; pnote_var noteVarTemp, noteVarTempBis; unsigned char i, j=0, w=0; %} %start composition %right ASSIGN %left OR %left AND %left EQ NE %left LT LE GT GE %left PLUS MINUS %left MULT DIVIDE MODULE %left UMINUS PLUSPLUS MINMIN NOT %left '(' %% open_parenthesis :'(' |error { sntx_err(EXPECTED, "open parenthesis "); } ; close_parenthesis :')' |error { sntx_err(EXPECTED, "closed parenthesis "); } ; expression :'(' expression ')' { $$=$2; } |id PLUSPLUS { ctrl[1]=$1; } stepPlus { $$=$4; } |id MINMIN { ctrl[1]=$1; } stepMin { $$=$4; } |MINUS expression %prec UMINUS { $$=-$2 } |expression MULT expression { $$=$1*$3; } |expression DIVIDE expression { $$=$1/$3; } |expression MODULE expression { $$=$1%$3; } |expression PLUS expression { $$=$1+$3; } |expression MINUS expression { $$=$1-$3; } |RAND open_parenthesis expression close_parenthesis { $$=rand()%$3; } |id |unsigned ; stepPlus : { $$=++ctrl[1]; ctrl[1]=0; } |STEP unsigned { $$=ctrl[1]+=$2; ctrl[1]=0; } ; stepMin : { $$=--ctrl[1]; ctrl[1]=0; } |STEP unsigned { $$=ctrl[1]-=$2; ctrl[1]=0; } ; bool_expr :'(' bool_expr ')' { $$=$2; } |NOT bool_expr { gen_exp3_code(_NOT, $2, ctrl[2]); $$=2; } |bool_expr { ($1<2)?(ctrlTemp[w++]=ctrl[2]):(ctrlTemp[w++]=ctrl[1]); } AND bool_expr { gen_exp1_code(_AND, $1, ctrlTemp[--w], $4, ctrl[2]); $$=2; } |bool_expr { ($1<2)?(ctrlTemp[w++]=ctrl[2]):(ctrlTemp[w++]=ctrl[1]); } OR bool_expr { gen_exp1_code(_OR, $1, ctrlTemp[--w], $4, ctrl[2]); $$=2; } |translate_expression { ($1<2)?(ctrlTemp[w++]=ctrl[2]):(ctrlTemp[w++]=ctrl[1]); } LT translate_expression { gen_exp1_code(_LT, $1, ctrlTemp[--w], $4, ctrl[2]); $$=2; } |translate_expression { ($1<2)?(ctrlTemp[w++]=ctrl[2]):(ctrlTemp[w++]=ctrl[1]); } LE translate_expression { gen_exp1_code(_LE, $1, ctrl[--w], $4, ctrl[2]); $$=2; } |translate_expression { ($1<2)?(ctrlTemp[w++]=ctrl[2]):(ctrlTemp[w++]=ctrl[1]); } GT translate_expression { gen_exp1_code(_GT, $1, ctrl[--w], $4, ctrl[2]); $$=2; } |translate_expression { ($1<2)?(ctrlTemp[w++]=ctrl[2]):(ctrlTemp[w++]=ctrl[1]); } GE translate_expression { gen_exp1_code(_GE, $1, ctrlTemp[--w], $4, ctrl[2]); $$=2; } |translate_expression { ($1<2)?(ctrlTemp[w++]=ctrl[2]):(ctrlTemp[w++]=ctrl[1]); } EQ translate_expression { gen_exp1_code(_EQ, $1, ctrlTemp[--w], $4, ctrl[2]); $$=2; } |translate_expression { ($1<2)?(ctrlTemp[w++]=ctrl[2]):(ctrlTemp[w++]=ctrl[1]); } NE translate_expression { gen_exp1_code(_NE, $1, ctrlTemp[--w], $4, ctrl[2]); $$=2; } |error { sntx_err(EXPECTED, "boolean expression "); } ; translate_expression :assign_expr { if(!ctrl[0] && $1==2 && !ctrl[13]) gen_exp4_code(_ENDEXP); j=0; $$=$1; } |expr { if(ctrl[16]) sntx_err(EXPECTED, "variable assignment "); if(!ctrl[0] && $1==2 && !ctrl[13]) gen_exp4_code(_ENDEXP); j=0; $$=$1; } ; assign_expr :'(' assign_expr ')' { $$=$2; } |asmId ASSIGN expr { if($3==2) { if(!ctrl[13]) gen_exp2_code(_MOV, $1, $3, ctrl[2]); $$=2; } else { if(!ctrl[13]) { if((players[playerCount]->productions[hash(idTemp, 0)]-> exp==NULL) && !(players[playerCount]->productions[hash(idTemp, 0)]-> exp=(pExp)malloc(sizeof(expression)))) sntx_err(MEMORY_ERR, ""); gen_exp2_code(_MOV, $1, $3, ctrl[2]); } $$=2; } } ; expr :'(' expr ')' { $$=$2; } |asmId PLUSPLUS stepAsm { if(!ctrl[13]) { if((players[playerCount]->productions[hash(idTemp, 0)]-> exp==NULL) && !(players[playerCount]->productions[hash(idTemp, 0)]-> exp=(pExp)malloc(sizeof(expression)))) sntx_err(MEMORY_ERR, ""); gen_exp3_code(_INC, $1, $3); } $$=2; } |asmId MINMIN stepAsm { if(!ctrl[13]) { if((players[playerCount]->productions[hash(idTemp, 0)]-> exp==NULL) && !(players[playerCount]->productions[hash(idTemp, 0)]-> exp=(pExp)malloc(sizeof(expression)))) sntx_err(MEMORY_ERR, ""); gen_exp3_code(_DEC, $1, $3); } $$=2; } |MINUS expr %prec UMINUS { if(!ctrl[13]) { if((players[playerCount]->productions[hash(idTemp, 0)]-> exp==NULL) && !(players[playerCount]->productions[hash(idTemp, 0)]-> exp=(pExp)malloc(sizeof(expression)))) sntx_err(MEMORY_ERR, ""); gen_exp3_code(_UMIN, $2, ctrl[2]); } $$=2; } |expr { if(!ctrl[13]) { if((players[playerCount]->productions[hash(idTemp, 0)]-> exp==NULL) && !(players[playerCount]->productions[hash(idTemp, 0)]-> exp=(pExp)malloc(sizeof(expression)))) sntx_err(MEMORY_ERR, ""); ($1<2)?(ctrlTemp[j++]=ctrl[2]):(ctrlTemp[j++]=ctrl[1]); } } MULT expr { if(!ctrl[13]) gen_exp1_code(_MUL, $1, ctrlTemp[--j], $4, ctrl[2]); $$=2; } |expr { if(!ctrl[13]) { if((players[playerCount]->productions[hash(idTemp, 0)]-> exp==NULL) && !(players[playerCount]->productions[hash(idTemp, 0)]-> exp=(pExp)malloc(sizeof(expression)))) sntx_err(MEMORY_ERR, ""); ($1<2)?(ctrlTemp[j++]=ctrl[2]):(ctrlTemp[j++]=ctrl[1]); } } DIVIDE expr { if(!ctrl[13]) gen_exp1_code(_DIV, $1, ctrlTemp[--j], $4, ctrl[2]); $$=2; } |expr { if(!ctrl[13]) { if((players[playerCount]->productions[hash(idTemp, 0)]-> exp==NULL) && !(players[playerCount]->productions[hash(idTemp, 0)]-> exp=(pExp)malloc(sizeof(expression)))) sntx_err(MEMORY_ERR, ""); ($1<2)?(ctrlTemp[j++]=ctrl[2]):(ctrlTemp[j++]=ctrl[1]); } } MODULE expr { if(!ctrl[13]) gen_exp1_code(_MOD, $1, ctrlTemp[--j], $4, ctrl[2]); $$=2; } |expr { if(!ctrl[13]) { if((players[playerCount]->productions[hash(idTemp, 0)]-> exp==NULL) && !(players[playerCount]->productions[hash(idTemp, 0)]-> exp=(pExp)malloc(sizeof(expression)))) sntx_err(MEMORY_ERR, ""); ($1<2)?(ctrlTemp[j++]=ctrl[2]):(ctrlTemp[j++]=ctrl[1]); } } PLUS expr { if(!ctrl[13]) gen_exp1_code(_ADD, $1, ctrlTemp[--j], $4, ctrl[2]); $$=2; } |expr { if(!ctrl[13]) { if((players[playerCount]->productions[hash(idTemp, 0)]-> exp==NULL) && !(players[playerCount]->productions[hash(idTemp, 0)]-> exp=(pExp)malloc(sizeof(expression)))) sntx_err(MEMORY_ERR, ""); ($1<2)?(ctrlTemp[j++]=ctrl[2]):(ctrlTemp[j++]=ctrl[1]); } } MINUS expr { if(!ctrl[13]) gen_exp1_code(_SUB, $1, ctrlTemp[--j], $4, ctrl[2]); $$=2; } |RAND open_parenthesis expr close_parenthesis { if(!ctrl[13]) { if((players[playerCount]->productions[hash(idTemp, 0)]-> exp==NULL) && !(players[playerCount]->productions[hash(idTemp, 0)]-> exp=(pExp)malloc(sizeof(expression)))) sntx_err(MEMORY_ERR, ""); /*if($3>1) sntx_err(EXPECTED, "variable or positive integer ");*/ gen_exp3_code(_RND, $3, ctrl[2]); } $$=2; } |asmId { ctrl[2]=$1; $$=1; } |unsigned { ctrl[2]=$1; $$=0; } ; id :IDENTIFIER { switch(isGlobal) { case 0: if(!(noteVarTempBis=(pnote_var)dhSearch(yytext, 0)) && !(noteVarTempBis=(pnote_var)dhSearch(yytext, 1))) sntx_err(VAR_NOT_DECLARED, ""); break; case 1: if(!(noteVarTempBis=(pnote_var)dhSearch(yytext, 1))) sntx_err(VAR_NOT_DECLARED, ""); } if(noteVarTempBis->type!=noteVarTemp->type) sntx_err(TYPE_ERR, ""); $$=noteVarTempBis->value; } ; stepAsm : { $$=1; } |STEP unsigned { $$=$2; } ; asmId :IDENTIFIER { $$=hash(yytext, 1); } ; composition :define_part composition_header orchestra ; define_part :COMPOSITION { back(); } |DEFINE { isDef=1; } IDENTIFIER { strcpy(idTemp, yytext); } string { if(++macroCount>NUM_MACRO) sntx_err(TOO_MANY_MACROS, ""); dhInsert(NULL, idTemp, 2); isDef=0; } define_part |error { if(isDef) sntx_err(EXPECTED, "identifier "); else sntx_err(EXPECTED, "keyword 'composition' "); } ; string :STRING |error { sntx_err(EXPECTED, "string "); } ; composition_header :COMPOSITION composition_title composition_author |error { sntx_err(EXPECTED, "keyword 'composition' "); } ; composition_title :STRING { if(!(title=(char *)malloc((1+strlen(string_buf)) *sizeof(char)))) sntx_err(MEMORY_ERR, ""); strcpy(title, string_buf); } |error { sntx_err(EXPECTED, "string "); } ; composition_author :OF author_data |error { sntx_err(EXPECTED, "keyword 'of' "); } author_data :STRING { if(!(copyright=(char *)malloc((1+strlen(string_buf)) *sizeof(char)))) sntx_err(MEMORY_ERR, ""); strcpy(copyright, string_buf); } |error { sntx_err(EXPECTED, "string "); } ; orchestra :'{' global_param_decl_part var_decl { isGlobal=0; } players_part |error { sntx_err(EXPECTED, "orchestra block "); } ; global_param_decl_part :'%' { ctrl[0]=ctrl[1]=ctrl[2]=ctrl[3]=ctrl[4]=ctrl[5]=ctrl[6]= ctrl[7]=ctrl[8]=ctrl[9]=ctrl[10]=0; } |GRAMMAR { if(ctrl[0]++) sntx_err(ALREADY, "keyword 'grammar' "); } grammar_type { grammarOption=$3; } global_param_decl_part |TEMPO { if(ctrl[1]++) sntx_err(ALREADY, "keyword 'tempo' "); } unsigned { if(($3<1) || ($3>300)) sntx_err(TEMPO_OUT, ""); tempo=$3; } global_param_decl_part |RESOLUTION { if(ctrl[2]++) sntx_err(ALREADY, "keyword 'resolution' "); } unsigned { if(($3<24) || ($3>960)) sntx_err(RES_OUT, ""); global_resolution=$3; } global_param_decl_part |ITERATIONS { if(ctrl[3]++) sntx_err(ALREADY, "keyword 'iterations' "); } unsigned { if($3<1) sntx_err(IT_OUT, ""); global_iterations=$3; } global_param_decl_part |TIME_SIGNATURE { if(ctrl[4]++) sntx_err(ALREADY, "keyword 'time_signature' "); } fraction global_param_decl_part |OCTAVE { if(ctrl[5]++) sntx_err(ALREADY, "keyword 'octave' "); } signed { if(($3<-2) || ($3>8)) sntx_err(OCTAVE_OUT, ""); global_params[DEFOCT]=$3; } global_param_decl_part |VELOCITY { if(ctrl[6]++) sntx_err(ALREADY, "keyword 'velocity' "); } unsigned { if($3>127) sntx_err(OUT, "'velocity' value "); global_params[DEFVEL]=$3; } global_param_decl_part ; |DURATION { if(ctrl[7]++) sntx_err(ALREADY, "keyword 'duration' "); } unsigned { global_params[DEFDUR]=$3; } global_param_decl_part |RELEASE { if(ctrl[8]++) sntx_err(ALREADY, "keyword 'release' "); } unsigned { if($3>127) sntx_err(OUT, "'release' value "); global_params[DEFREL]=$3; } global_param_decl_part |MSB { if(ctrl[9]++) sntx_err(ALREADY, "keyword 'msb' "); } unsigned { if($3>127) sntx_err(OUT, "'msb' value "); global_params[DEFMSB]=$3; } global_param_decl_part |INSTRUMENT { if(ctrl[10]++) sntx_err(ALREADY, "keyword 'instrument' "); } unsigned { if($3>127) sntx_err(OUT, "'instrument' value "); global_params[DEFINSTR]=$3; } global_param_decl_part ; grammar_type :CHOMSKY { $$=$1; } |LINDENMAYER { $$=$1; } |error { sntx_err(EXPECTED, "grammar type "); } ; unsigned :NUMBER { $$=$1; } |error { sntx_err(EXPECTED, "positive integer "); } ; signed :NUMBER { $$=$1; } |MINUS NUMBER { $$=-$2; } |error { sntx_err(EXPECTED, "positive or negative integer "); } ; fraction :NUMBER { if(($1<1) || ($1>64)) sntx_err(NUMERATOR_OUT, ""); if(isGlobal) glob_num=$1; else players[playerCount]->num=$1; } div unsigned { if($4!=1 && $4!=2 && $4!=4 &&$4!=8 && $4!=16 && $4!=32 && $4!=64) sntx_err(FRACTION_DEN_ERR, ""); if(isGlobal) glob_den=$3; else players[playerCount]->den=$3; } |error { sntx_err(EXPECTED, "fraction of form num/den "); } ; div :DIVIDE |error { sntx_err(EXPECTED, "fraction symbol '/' "); } ; var_decl :PLAYER { ctrl[0]=0; back(); } |AXIOM { ctrl[0]=0; back(); } |AT_COMPOSITION { ctrl[0]=ctrl[1]=0; back(); } |type { noteVarTemp->type=ctrl[0]; } assign_list semicolon var_decl |error { if(isGlobal) sntx_err(PLAYER_EXPECTED, ""); else switch(players[playerCount]->grammar) { case 0: switch(grammarOption) { case 1: sntx_err(EXPECTED, "@composition production "); case 2: sntx_err(EXPECTED, "axiom production "); } case 1: sntx_err(EXPECTED, "@composition production "); case 2: sntx_err(EXPECTED, "axiom production "); } } ; semicolon :';' |error { sntx_err(EXPECTED, "semicolon "); } type :OCTAVE { ctrl[0]=OCT; } |VELOCITY { ctrl[0]=VEL; } |DURATION { ctrl[0]=DUR; } |RELEASE { ctrl[0]=REL; } |MSB { ctrl[0]=BYTEDATA; } ; assign_list :assign |assign_list comma assign |error { sntx_err(EXPECTED, "identifier "); } ; comma :',' |error { sntx_err(EXPECTED, "comma "); } assign :IDENTIFIER { if(++varCount>NUM_VARS) sntx_err(TOO_MANY_VARS, ""); strcpy(noteVarTemp->name, yytext); } inizialization ; inizialization : { dhInsert(noteVarTemp, "", isGlobal); } |ASSIGN expression { switch(ctrl[0]) { case OCT: $$=$2; if($$<-2) $$=-2; if($$>8) $$=8; break; case DUR: if(($$=$2)<0) $$=0; break; case BYTEDATA: $$=$2; if($$<-127) $$=-127; if($$>127) $$=127; break; default: $$=$2; if($$<0) $$=0; if($$>127) $$=127; } //printf("%s %d\n", noteVarTemp->name, $$); DEBUG LINE! noteVarTemp->value=$$; dhInsert(noteVarTemp, "", isGlobal); } ; players_part :'}' |player_part { playerCount++; } players_part |error { sntx_err(EXPECTED, "end of orchestra block ('}') "); } ; player_part :PLAYER { init_local_flag(); if(playerCount>NUM_PLAYERS) sntx_err(TOO_MANY_PLAYERS, ""); init_player(); varCount=0; } IDENTIFIER { if(!(players[playerCount]->identifier=(char *) malloc((1+strlen(yytext)) *sizeof(char)))) sntx_err(MEMORY_ERR, ""); strcpy(players[playerCount]->identifier, yytext); } player_block |error { sntx_err(EXPECTED, "identifier "); } ; player_block :'{' local_param_decl_part var_decl player_productions |error { sntx_err(EXPECTED, "player block "); } ; local_param_decl_part :'%' { if(!loc_par_flag[0] && !grammarOption) sntx_err(GRAMMAR_EXPECTED, ""); } |GRAMMAR { if(loc_par_flag[0]++) sntx_err(ALREADY, "keyword 'grammar' "); } grammar_type { players[playerCount]->grammar=$3; } local_param_decl_part |ITERATIONS { if(loc_par_flag[1]++) sntx_err(ALREADY, "keyword 'iterations' "); } unsigned { if($3<1) sntx_err(IT_OUT, ""); players[playerCount]->iterations=$3; } local_param_decl_part |TIME_SIGNATURE { if(loc_par_flag[2]++) sntx_err(ALREADY, "keyword 'time_signature' "); } fraction local_param_decl_part |OCTAVE { if(loc_par_flag[3]++) sntx_err(ALREADY, "keyword 'octave' "); } signed { if(($3<-2) || ($3>8)) sntx_err(OCTAVE_OUT, ""); players[playerCount]->local_params[DEFOCT]=$3; } local_param_decl_part |VELOCITY { if(loc_par_flag[4]++) sntx_err(ALREADY, "keyword 'velocity' "); } unsigned { if($3>127) sntx_err(OUT, "'velocity' value "); players[playerCount]->local_params[DEFVEL]=$3; } local_param_decl_part |DURATION { if(loc_par_flag[5]++) sntx_err(ALREADY, "keyword 'duration' "); } unsigned { players[playerCount]->local_params[DEFDUR]=$3; } local_param_decl_part |RELEASE { if(loc_par_flag[6]++) sntx_err(ALREADY, "keyword 'release' "); } unsigned { if($3>127) sntx_err(OUT, "'release' value "); players[playerCount]->local_params[DEFREL]=$3; } local_param_decl_part |MSB { if(loc_par_flag[7]++) sntx_err(ALREADY, "keyword 'msb' "); } unsigned { if($3>127) sntx_err(OUT, "'msb' value "); players[playerCount]->local_params[DEFMSB]=$3; } local_param_decl_part |INSTRUMENT { if(loc_par_flag[8]++) sntx_err(ALREADY, "keyword 'instrument' "); } unsigned { if($3>127) sntx_err(OUT, "'instrument' value "); players[playerCount]->local_params[DEFINSTR]=$3; } local_param_decl_part |CHANNEL { if(loc_par_flag[9]++) sntx_err(ALREADY, "keyword 'channel' "); } unsigned { if($3>15) sntx_err(CHN_OUT, ""); players[playerCount]->local_params[CHN]=$3; } local_param_decl_part |error { if(!loc_par_flag[0] && !grammarOption) sntx_err(GRAMMAR_EXPECTED, ""); else sntx_err(EXPECTED, "'%' "); } ; player_productions :chomsky_composition_prod |lindenmayer_axiom_prod ; chomsky_composition_prod :AT_COMPOSITION { switch(players[playerCount]->grammar) { case 0: if(grammarOption==2) sntx_err(EXPECTED, "axiom production "); break; case 2: sntx_err(EXPECTED, "axiom production "); } strcpy(idTemp, yytext); dhInsert(NULL, idTemp, 3, 0); } condition chomsky_prod_assign alternative_chomsky chomsky_productions ; condition :PROD { back(); } |COND { ctrl[17]++; if((players[playerCount]->productions[hash(idTemp, 0)]-> exp==NULL) && !(players[playerCount]->productions[hash(idTemp, 0)]-> exp=(pExp)malloc(sizeof(expression)))) sntx_err(MEMORY_ERR, ""); ec=players[playerCount]->productions[hash(idTemp, 0)]->ec; //gen_code(_EXP, ); ctrl[0]++; } bool_expr { w=0; gen_exp4_code(_ENDEXP); //gen_code2(_CHK, ec); gen_code(_CHK, ec); ccCond=(players[playerCount]->productions[hash(idTemp, 0)]->cc)-1; ctrl[0]=ctrl[1]=ctrl[2]=ctrl[3]=0; } |error { sntx_err(EXPECTED, "condition or operator '->' "); } ; alternative_chomsky : |ELSE { (!ctrl[17])?(sntx_err(ELSE_WITHOUT_CONDITION, "")):(ctrl[17]++); gen_code2(_ELSE); gen_code(_PRD_ALT, players[playerCount] ->productions[hash(idTemp, 0)]->numOrAlt); cc=(players[playerCount]->productions[hash(idTemp, 0)]->cc)-1; code_update(cc, ccCond); } chomsky_prod_body ; alternative_lindenmayer : |ELSE { (!ctrl[17])?(sntx_err(ELSE_WITHOUT_CONDITION, "")):(ctrl[17]++); gen_code2(_ELSE); gen_code(_PRD_ALT, players[playerCount] ->productions[hash(idTemp, 0)]->numOrAlt); cc=(players[playerCount]->productions[hash(idTemp, 0)]->cc)-1; code_update(cc, ccCond); } lindenmayer_prod_body ; chomsky_prod_assign :PROD { if(players[playerCount]->productions[hash(idTemp, 0)]->numOr==1) gen_code(_PRD, players[playerCount] ->productions[hash(idTemp, 0)]->numOr); } chomsky_prod_body |error { sntx_err(EXPECTED, "operator '->' "); } ; chomsky_prod_body :';' { if(ctrl[17]==2) ctrl[17]=0; } |chomsky_seq chomsky_prod_body |error { sntx_err(EXPECTED, "semicolon "); } ; chomsky_seq :note { (ctrl[4]<0)?(gen_note_code(_EMPTY, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12])):(gen_note_code(_NOTEON, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12])); ctrl[4]=ctrl[5]=ctrl[6]=ctrl[7]=ctrl[8]=ctrl[9]=ctrl[10]=ctrl[11]=ctrl[12]=0; } |CHORD { gen_code2(_CHORD); } note_seq |DEFNOTE { ctrl[4]=$1; if(loc_par_flag[4]) ctrl[5]=players[playerCount]->local_params[DEFOCT]; else ctrl[5]=global_params[DEFOCT]; if(loc_par_flag[5]) ctrl[6]=players[playerCount]->local_params[DEFVEL]; else ctrl[6]=global_params[DEFVEL]; if(loc_par_flag[6]) ctrl[7]=players[playerCount]->local_params[DEFDUR]; else ctrl[7]=global_params[DEFDUR]; if(loc_par_flag[7]) ctrl[8]=players[playerCount]->local_params[DEFREL]; else ctrl[8]=global_params[DEFREL]; (ctrl[4]<0)?(gen_note_code(_EMPTY, ctrl[4], 0, ctrl[5], 0, ctrl[6], 0, ctrl[7], 0, ctrl[8])):(gen_note_code(_NOTEON, ctrl[4], 0, ctrl[5], 0, ctrl[6], 0, ctrl[7], 0, ctrl[8])); ctrl[4]=ctrl[5]=ctrl[6]=ctrl[7]=ctrl[8]=0; } |REST begin duration { gen_code3(_REST, ctrl[9], ctrl[10]); ctrl[1]=ctrl[2]=ctrl[3]=ctrl[9]=ctrl[10]=0; } end |AT_COMPOSITION { gen_code(_GOTO, hash(yytext, 0)); } |NON_TERMINAL { if(!players[playerCount]->productions[hash(yytext, 0)]) dhInsert(NULL, yytext, 3, 1); gen_code(_GOTO, hash(yytext, 0)); } |TRANSPOSE open_parenthesis msb { gen_code3(_TRN, ctrl[4], ctrl[5]); } comma melodic_op_chomsky_seq { ctrl[1]=ctrl[2]=ctrl[3]=ctrl[4]=ctrl[5]=0; } |INVERSION { gen_code2(_INV); } open_parenthesis melodic_op_chomsky_seq |RETROGRADE { gen_code2(_RTRGD); } open_parenthesis melodic_op_chomsky_seq |RETROGRADE_INV { gen_code2(_RTGINV); } open_parenthesis melodic_op_chomsky_seq |REPEAT open_parenthesis msb { gen_code3(_REP, ctrl[4], ctrl[5]); ctrl[15]++; } comma chomsky_rep_seq |UPDATE begin { ctrl[16]++; } exp_init translate_expression { gen_code3(_UPDATE, ec, ctrl[3]); } end { ctrl[1]=ctrl[2]=ctrl[3]=ctrl[16]=0; } |NONDET { if(ctrl[15]) sntx_err(REPEAT_ERR, ""); (ctrl[17]==2)?(gen_code(_PRD_ALT, ++players[playerCount]->productions[hash(idTemp, 0)]->numOrAlt)):(gen_code(_PRD, ++players[playerCount]->productions[hash(idTemp, 0)]->numOr)); } |PRINT open_parenthesis exp_init print_seq close_parenthesis ; print_seq : |translate_expression { ctrl[5]=_EXP; if(!ctrl[13]) ctrl[6]=ec; switch($1) { case 0: ctrl[5]=0; ctrl[6]=ctrl[2]; break; case 1: ctrl[5]=1; ctrl[6]=ctrl[2]; } gen_code4(_PRNT, ctrl[5], ctrl[6], ctrl[3]); ctrl[1]=ctrl[2]=ctrl[3]=ctrl[4]=ctrl[5]=ctrl[6]=0; } print_seq exp_init |STRING { if(stringCount>MAX_STR) sntx_err(TOO_MANY_STRINGS, ""); if(!(strings[stringCount]=(char *)malloc((1+strlen(string_buf)) *sizeof(char)))) sntx_err(MEMORY_ERR, ""); strcpy(strings[stringCount], string_buf); gen_code3(_PRNT, _STR, stringCount++); } print_seq ; chomsky_rep_seq :close_parenthesis { gen_code2(_ENDREP); ctrl[15]=0; } |chomsky_seq chomsky_rep_seq ; endchord :CHORD |error { sntx_err(EXPECTED, "end of chord '^' "); } ; note_seq :endchord { gen_code2(_ENDCHORD); } |note { (ctrl[4]<0)?(gen_note_code(_EMPTY, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12])):(gen_note_code(_NOTEON, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12])); ctrl[4]=ctrl[5]=ctrl[6]=ctrl[7]=ctrl[8]=ctrl[9]=ctrl[10]= ctrl[11]=ctrl[12]=0; } note_seq |AT_COMPOSITION { gen_code(_GOTO, hash(yytext, 0)); } note_seq |NON_TERMINAL { if(!players[playerCount]->productions[hash(yytext, 0)]) dhInsert(NULL, yytext, 3, 1); gen_code(_GOTO, hash(yytext, 0)); } note_seq |REST begin duration { gen_code3(_REST, ctrl[9], ctrl[10]); ctrl[1]=ctrl[2]=ctrl[3]=ctrl[9]=ctrl[10]=0; } end note_seq ; note_seq_bis :endchord { gen_code2(_ENDCHORD); } |note { (ctrl[4]<0)?(gen_note_code(_EMPTY, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12])):(gen_note_code(_NOTEON, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12])); ctrl[4]=ctrl[5]=ctrl[6]=ctrl[7]=ctrl[8]=ctrl[9]=ctrl[10]= ctrl[11]=ctrl[12]=0; } note_seq_bis |REST begin duration { gen_code3(_REST, ctrl[9], ctrl[10]); ctrl[1]=ctrl[2]=ctrl[3]=ctrl[9]=ctrl[10]=0; } end note_seq_bis ; note_seq_tre :endchord { //strcat(idTemp, yytext); } |note { if(ctrl[4]<0) sntx_err(SILENT_ERR, ""); if(ctrl[5]|ctrl[7]|ctrl[9]|ctrl[11]) sntx_err(EXPECTED, "constant chord "); sprintf(string_buf, "%d%d%d%d%d", ctrl[4], ctrl[6], ctrl[8], ctrl[10], ctrl[12]); strcat(idTemp, string_buf); strcpy(string_buf, ""); ctrl[4]=ctrl[5]=ctrl[6]=ctrl[7]=ctrl[8]=ctrl[9]=ctrl[10]= ctrl[11]=ctrl[12]=0; } note_seq_tre |REST begin duration { if(ctrl[9]) sntx_err(EXPECTED, "constant chord "); sprintf(string_buf, "%d", ctrl[10]); strcat(idTemp, string_buf); strcpy(string_buf, ""); ctrl[4]=ctrl[9]=ctrl[10]=0; } end note_seq_tre ; melodic_op_chomsky_seq :close_parenthesis { gen_code2(_ENDMELOP); } |note { (ctrl[4]<0)?(gen_note_code(_EMPTY, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12])):(gen_note_code(_NOTEON, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12])); ctrl[4]=ctrl[5]=ctrl[6]=ctrl[7]=ctrl[8]=ctrl[9]=ctrl[10]= ctrl[11]=ctrl[12]=0; } melodic_op_chomsky_seq |REST begin duration { gen_code3(_REST, ctrl[9], ctrl[10]); ctrl[1]=ctrl[2]=ctrl[3]=ctrl[9]=ctrl[10]=0; } end melodic_op_chomsky_seq |CHORD { gen_code2(_CHORD); } note_seq melodic_op_chomsky_seq |NON_TERMINAL { if(!players[playerCount]->productions[hash(yytext, 0)]) dhInsert(NULL, yytext, 3, 1); gen_code(_GOTO, hash(yytext, 0)); } melodic_op_chomsky_seq |AT_COMPOSITION { gen_code(_GOTO, hash(yytext, 0)); } melodic_op_chomsky_seq |TRANSPOSE open_parenthesis exp_init msb { gen_code3(_TRN, ctrl[4], ctrl[5]); } comma melodic_op_chomsky_seq melodic_op_chomsky_seq { ctrl[1]=ctrl[2]=ctrl[3]=ctrl[4]=ctrl[5]=0; } |INVERSION { gen_code2(_INV); } open_parenthesis melodic_op_chomsky_seq melodic_op_chomsky_seq |RETROGRADE { gen_code2(_RTRGD); } open_parenthesis melodic_op_chomsky_seq melodic_op_chomsky_seq |RETROGRADE_INV { gen_code2(_RTGINV); } open_parenthesis melodic_op_chomsky_seq melodic_op_chomsky_seq ; exp_init : { if(!ctrl[13]) ec=players[playerCount]->productions[hash(idTemp, 0)]->ec; } ; note :NOTE { ctrl[4]=$1; } begin exp_init octave comma { ctrl[1]=ctrl[2]=ctrl[3]=0; } exp_init velocity comma { ctrl[1]=ctrl[2]=ctrl[3]=0; } exp_init duration comma { ctrl[1]=ctrl[2]=ctrl[3]=0; } exp_init release { ctrl[1]=ctrl[2]=ctrl[3]=0; } end ; begin :'[' |error { sntx_err(EXPECTED, "'[' "); } ; end :']' |error { sntx_err(EXPECTED, "']' "); } ; octave : { ctrl[5]=0; if(loc_par_flag[3]) ctrl[6]=players[playerCount]->local_params[DEFOCT]; else ctrl[6]=global_params[DEFOCT]; } |translate_expression { if(ctrl[3] && ctrl[3]!=OCT) sntx_err(EXPECTED, "variable of type octave "); ctrl[5]=_EXP; if(!ctrl[13]) ctrl[6]=ec; switch($1) { case 0: ctrl[5]=0; if(ctrl[2]>8) ctrl[2]=8; if(ctrl[2]<-2) ctrl[2]=-2; ctrl[6]=ctrl[2]; break; case 1: ctrl[5]=1; ctrl[6]=ctrl[2]; } } ; velocity : { ctrl[7]=0; if(loc_par_flag[4]) ctrl[8]=players[playerCount]->local_params[DEFVEL]; else ctrl[8]=global_params[DEFVEL]; } |translate_expression { if(ctrl[3] && ctrl[3]!=VEL) sntx_err(EXPECTED, "variable of type velocity "); ctrl[7]=_EXP; if(!ctrl[13]) ctrl[8]=ec; switch($1) { case 0: ctrl[7]=0; if(ctrl[2]>127) ctrl[2]=127; if(ctrl[2]<0) ctrl[2]=0; ctrl[8]=ctrl[2]; break; case 1: ctrl[7]=1; ctrl[8]=ctrl[2]; } } ; duration : { ctrl[9]=0; if(loc_par_flag[5]) ctrl[10]=players[playerCount]->local_params[DEFDUR]; else ctrl[10]=global_params[DEFDUR]; } |translate_expression { if(ctrl[3] && ctrl[3]!=DUR) sntx_err(EXPECTED, "variable of type duration "); ctrl[9]=_EXP; if(!ctrl[13]) ctrl[10]=ec; switch($1) { case 0: ctrl[9]=0; if(ctrl[2]<0) ctrl[2]=0; ctrl[10]=ctrl[2]; break; case 1: ctrl[9]=1; ctrl[10]=ctrl[2]; } } ; release : { ctrl[11]=0; if(loc_par_flag[6]) ctrl[12]=players[playerCount]->local_params[DEFREL]; else ctrl[12]=global_params[DEFREL]; } |translate_expression { if(ctrl[3] && ctrl[3]!=REL) sntx_err(EXPECTED, "variable of type release "); ctrl[11]=_EXP; if(!ctrl[13]) ctrl[12]=ec; switch($1) { case 0: ctrl[11]=0; if(ctrl[2]>127) ctrl[2]=127; if(ctrl[2]<0) ctrl[2]=0; ctrl[12]=ctrl[2]; break; case 1: ctrl[11]=1; ctrl[12]=ctrl[2]; } } ; msb : { ctrl[4]=0; if(loc_par_flag[7]) ctrl[5]=players[playerCount]->local_params[DEFMSB]; else ctrl[5]=global_params[DEFMSB]; } |translate_expression { if(ctrl[3] && ctrl[3]!=BYTEDATA) sntx_err(EXPECTED, "variable of type msb "); ctrl[4]=_EXP; if(!ctrl[13]) ctrl[5]=ec; switch($1) { case 0: ctrl[4]=0; if(ctrl[2]>127) ctrl[2]=127; if(ctrl[2]<-127) ctrl[2]=-127; ctrl[5]=ctrl[2]; break; case 1: ctrl[4]=1; ctrl[5]=ctrl[2]; } } ; chomsky_productions :'}' |NON_TERMINAL { strcpy(idTemp, yytext); dhInsert(NULL, idTemp, 3, 0); } condition chomsky_prod_assign alternative_chomsky chomsky_productions |error { sntx_err(EXPECTED, "end of player block ('}') "); } ; lindenmayer_axiom_prod :AXIOM { switch(players[playerCount]->grammar) { case 0: if(grammarOption==1) sntx_err(EXPECTED, "@composition production "); break; case 1: sntx_err(EXPECTED, "@composition production "); } strcpy(idTemp, yytext); dhInsert(NULL, idTemp, 3, 0); } condition lindenmayer_prod_assign { ctrl[13]++; } alternative_lindenmayer lindenmayer_productions ; lindenmayer_prod_assign :PROD { gen_code(_PRD, players[playerCount] ->productions[hash(idTemp, 0)]->numOr); } lindenmayer_prod_body |error { sntx_err(EXPECTED, "operator '->' "); } ; lindenmayer_prod_body :';' { if(ctrl[17]==2) ctrl[17]=0; } |lindenmayer_seq lindenmayer_prod_body |error { sntx_err(EXPECTED, "semicolon "); } ; lindenmayer_seq :note { (ctrl[4]<0)?(gen_note_code(_EMPTY, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12])):(gen_note_code(_NOTEON, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12])); ctrl[4]=ctrl[5]=ctrl[6]=ctrl[7]=ctrl[8]=ctrl[9]=ctrl[10]= ctrl[11]=ctrl[12]=0; } |CHORD { gen_code2(_CHORD); } note_seq_bis |DEFNOTE { ctrl[4]=$1; if(loc_par_flag[4]) ctrl[5]=players[playerCount]->local_params[DEFOCT]; else ctrl[5]=global_params[DEFOCT]; if(loc_par_flag[5]) ctrl[6]=players[playerCount]->local_params[DEFVEL]; else ctrl[6]=global_params[DEFVEL]; if(loc_par_flag[6]) ctrl[7]=players[playerCount]->local_params[DEFDUR]; else ctrl[7]=global_params[DEFDUR]; if(loc_par_flag[7]) ctrl[8]=players[playerCount]->local_params[DEFREL]; else ctrl[8]=global_params[DEFREL]; (ctrl[4]<0)?(gen_note_code(_EMPTY, ctrl[4], 0, ctrl[5], 0, ctrl[6], 0, ctrl[7], 0, ctrl[8])):(gen_note_code(_NOTEON, ctrl[4], 0, ctrl[5], 0, ctrl[6], 0, ctrl[7], 0, ctrl[8])); ctrl[4]=ctrl[5]=ctrl[6]=ctrl[7]=ctrl[8]=0; } |REST begin duration { gen_code3(_REST, ctrl[9], ctrl[10]); ctrl[1]=ctrl[2]=ctrl[3]=ctrl[9]=ctrl[10]=0; } end |TRANSPOSE open_parenthesis msb { gen_code3(_TRN, ctrl[4], ctrl[5]); if(ctrl[17]==2) { cc=(players[playerCount]->productions[hash(idTemp, 0)]->cc)-1; code_update(cc, ccCond); ctrl[17]=0; } } comma melodic_op_lindenmayer_seq { ctrl[1]=ctrl[2]=ctrl[3]=ctrl[4]=ctrl[5]=0; } |INVERSION { gen_code2(_INV); } open_parenthesis melodic_op_lindenmayer_seq |RETROGRADE { gen_code2(_RTRGD); } open_parenthesis melodic_op_lindenmayer_seq |RETROGRADE_INV { gen_code2(_RTGINV); } open_parenthesis melodic_op_lindenmayer_seq |REPEAT open_parenthesis msb { gen_code3(_REP, ctrl[4], ctrl[5]); } comma lindenmayer_rep_seq |UPDATE begin { ctrl[16]++; } exp_init translate_expression { gen_code3(_UPDATE, ec, ctrl[3]); } end { ctrl[1]=ctrl[2]=ctrl[3]=ctrl[16]=0; } |NONDET { (ctrl[17]==2)?(gen_code(_PRD_ALT, ++players[playerCount]->productions[hash(idTemp, 0)]->numOrAlt)):(gen_code(_PRD, ++players[playerCount]->productions[hash(idTemp, 0)]->numOr)); } |PRINT open_parenthesis print_seq close_parenthesis ; melodic_op_lindenmayer_seq :close_parenthesis { gen_code2(_ENDMELOP); } |note { (ctrl[4]<0)?(gen_note_code(_EMPTY, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12])):(gen_note_code(_NOTEON, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12])); ctrl[4]=ctrl[5]=ctrl[6]=ctrl[7]=ctrl[8]=ctrl[9]=ctrl[10]= ctrl[11]=ctrl[12]=0; } melodic_op_chomsky_seq |CHORD { gen_code2(_CHORD); } note_seq_bis melodic_op_lindenmayer_seq |REST begin duration { gen_code3(_REST, ctrl[9], ctrl[10]); ctrl[1]=ctrl[2]=ctrl[3]=ctrl[9]=ctrl[10]=0; } end melodic_op_chomsky_seq |TRANSPOSE open_parenthesis msb { gen_code3(_TRN, ctrl[4], ctrl[5]); } comma melodic_op_lindenmayer_seq melodic_op_lindenmayer_seq { ctrl[1]=ctrl[2]=ctrl[3]=ctrl[4]=ctrl[5]=0; } |INVERSION { gen_code2(_INV); } open_parenthesis melodic_op_lindenmayer_seq melodic_op_lindenmayer_seq |RETROGRADE { gen_code2(_RTRGD); } open_parenthesis melodic_op_lindenmayer_seq melodic_op_lindenmayer_seq |RETROGRADE_INV { gen_code2(_RTGINV); } open_parenthesis melodic_op_lindenmayer_seq melodic_op_lindenmayer_seq ; lindenmayer_rep_seq :close_parenthesis { gen_code2(_ENDREP); } |lindenmayer_seq lindenmayer_rep_seq ; lindenmayer_productions :'}' |note { if(ctrl[4]<0) sntx_err(SILENT_ERR, ""); if(ctrl[5]|ctrl[7]|ctrl[9]|ctrl[11]) sntx_err(EXPECTED, "constant note "); strcpy(idTemp, ""); sprintf(string_buf, "%d%d%d%d%d", ctrl[4], ctrl[6], ctrl[8], ctrl[10], ctrl[12]); strcat(idTemp, string_buf); strcpy(string_buf, ""); dhInsert(NULL, idTemp, 3, 0); ctrl[4]=ctrl[5]=ctrl[6]=ctrl[7]=ctrl[8]=ctrl[9]=ctrl[10]= ctrl[11]=ctrl[12]=ctrl[13]=0; } condition lindenmayer_prod_assign { ctrl[13]++; } alternative_lindenmayer lindenmayer_productions |CHORD { strcpy(idTemp, ""); //strcat(idTemp, yytext); } note_seq_tre { dhInsert(NULL, idTemp, 3, 0); ctrl[13]=0; } condition lindenmayer_prod_assign { ctrl[13]++; } alternative_lindenmayer lindenmayer_productions |REST begin duration { if(ctrl[9]) sntx_err(EXPECTED, "constant note "); strcpy(idTemp, ""); sprintf(string_buf, "%d", ctrl[10]); strcat(idTemp, string_buf); strcpy(string_buf, ""); dhInsert(NULL, idTemp, 3, 0); ctrl[4]=ctrl[9]=ctrl[10]=ctrl[13]=0; } end condition lindenmayer_prod_assign { ctrl[13]++; } alternative_lindenmayer lindenmayer_productions |error { sntx_err(EXPECTED, "end of player block ('}') "); } ; %% int yyerror() { } int back() { yyless(0); } gramophone-0.8.13a/INSTALL0000644000175000017500000000071710757737531015366 0ustar giovannigiovanniREQUISITES In order to succesfully compile and install GRAMophone II, you must have installed on your box the GNU/Flex lexical analyzer generator, the GNU/Bison parser generator and of course the GNU/gcc compiler. COMPILE & INSTALL To compile and install, simply type: make make install enjoy! UNINSTALL Type: make uninstall GNU/LINUX USERS in Makefile, decomment CFLAGS+=-O2 -lm and comment CFLAGS+=-O2 WINDOWS USERS Rename Makefile.win32 to Makefilegramophone-0.8.13a/KNOWBUGS0000644000175000017500000000073710757737531015521 0ustar giovannigiovanniPrinting sub expressions gives strange results. For example the production: @composition->print(3-1); print "3-1"! For now I don't know why, but you can avoid this strange effect writing the previous production in this way: @composition->print((3-1)); This works and print the correct result 2. Another related problem appears parsing sub expressions in note parameters. for example: @composition->A[4-2,,,]; You can avoid this problem writing: @composition->[(4-2),,,];gramophone-0.8.13a/Makefile0000644000175000017500000000152410757737560015774 0ustar giovannigiovanniCC=gcc #CFLAGS+=-O2 #Decomment this line if you use Linux: CFLAGS+=-O2 -lm DESTDIR=/usr/local default: GRAMophone.tab.c $(CC) $(CFLAGS) -o gramophone2 GRAMophone.c\ grammyVM.c init.c midicode.c\ midifile.c expcode.c debug.c errors.c\ hash.c GRAMophone.tab.c GRAMophone.tab.c: lex.yy.c bison -d GRAMophone.y lex.yy.c: flex GRAMophone.l clean: rm -f y* lex* GRAMophone.tab.* gramophone2 install: mkdir -p $(DESTDIR)/bin install gramophone2 $(DESTDIR)/bin install -d $(DESTDIR)/share/man/man1 install -m 0644 man/man1/gramophone2.1 $(DESTDIR)/share/man/man1 install -d $(DESTDIR)/share/man/it/man1 install -m 0644 man/it/man1/gramophone2.1 $(DESTDIR)/share/man/it/man1 uninstall: rm -f $(DESTDIR)/bin/gramophone2\ $(DESTDIR)/share/man/man1/gramophone2.1\ $(DESTDIR)/share/man/it/man1/gramophone2.1 gramophone-0.8.13a/Makefile.win320000644000175000017500000000064710757737531016740 0ustar giovannigiovanniCC=gcc #with mingw32 O2 optimization GRAMophone crashes... CFLAGS+=-lm DESTDIR=$(HOMEPATH)\gramophone2 default: GRAMophone.tab.c $(CC) $(CFLAGS) -o gramophone2 GRAMophone.c\ grammyVM.c init.c midicode.c\ midifile.c expcode.c debug.c errors.c\ hash.c GRAMophone.tab.c GRAMophone.tab.c: lex.yy.c bison -d GRAMophone.y lex.yy.c: flex GRAMophone.l clean: del y* lex* GRAMophone.tab.* gramophone2.exe gramophone-0.8.13a/TODO0000644000175000017500000000026710757737531015025 0ustar giovannigiovanniThings to do: * a special global variable "iteration" that returns the current iteration number * a configuration file for memory settings * a gui? maybe... * a lot of testing... ;) gramophone-0.8.13a/debug.c0000644000175000017500000000551110757737531015564 0ustar giovannigiovanni/* * GRAMophone II, a grammar based algorithmic musical composition tool * -------------------------------------------------------------------- * * debug.c * * Copyright (c) 2007, Giovanni Ferranti * * GRAMophone II is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ------------------------------------------------------------------- */ #include "global.h" void print_composition_info() { printf("Composition Info:\n\n"); printf("Title: %s\nAuthor and Copyright: %s\n", title, copyright); printf("\n"); } void print_global_params() { register unsigned char i; printf("Global Parameters:\n\n"); printf("Default grammar: %d\n", grammarOption); printf("Default iterations: %d\n", global_iterations); printf("Default resolution: %d\n", global_resolution); printf("Default time signature: %d/%d\n", glob_num, glob_den); printf("Default tempo: %d\n", tempo); for(i=0; iidentifier); printf("Local Parameters:\n\n"); if(players[i]) { printf("Grammar: %d\n", players[i]->grammar); //printf("Time signature: %d/%d\n", players[i]->num, players[i]->den); printf("Iterations: %d\n", players[i]->iterations); for(j=0; jlocal_params[j]); printf("\n"); } printf("\n"); } void print_expression_memory_map() { register unsigned int i, j, w=0; for(i=0; iproductions[j]) if(players[i]->productions[j]->exp) while(players[i]->productions[j]->exp->expcode[w][0]) { printf("%d ", players[i]->productions[j]->exp->expcode[w][0]); printf("%d ", players[i]->productions[j]->exp->expcode[w][1]); printf("%d ", players[i]->productions[j]->exp->expcode[w][2]); printf("%d ", players[i]->productions[j]->exp->expcode[w][3]); printf("%d ", players[i]->productions[j]->exp->expcode[w++][4]); printf("\n"); } } gramophone-0.8.13a/errors.c0000644000175000017500000000452410757737531016015 0ustar giovannigiovanni/* * GRAMophone II, a grammar based algorithmic musical composition tool * -------------------------------------------------------------------- * * errors.c * * Copyright (c) 2007, Giovanni Ferranti * * GRAMophone II is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * -------------------------------------------------------------------- */ #include "global.h" extern int row; void sntx_err(unsigned int error, char *msg) { static char *e[]={ "unterminated string costant.", "end of file reached!", "discographies nested too deeply!", "discography not found!", "expected.", "memory allocation error!", "already defined.", "which grammar do you want to use?", "'resolution' value out of range 24..960", "a composition must have at least 1 iteration.", "out of range 0..127", "fraction's numerator out of range 1..64", "fraction's denominator can be: 1, 2, 4, 8, 16, 32 or 64.", "'octave' value out of range -2..8", "'tempo' value out of range 1..300", "...and the player(s)?", "variable not declared.", "too long.", "'channel' value out of range 0..15", "too many players!", "too many variables!", "incompatible type in expression.", "too many macros!", "too many note parameters!", "or not allowed in repeat arguments with chomsky grammar.", "silent note not allowed in the head of production.", "too many strings!", "...and the first condition?" }; fprintf(stderr, "Error!\n"); fprintf(stderr, "GRAMophone row %d: %s%s\n", row, msg, e[error]); exit(1); } void usageError(void) { fprintf(stderr, "Usage: gramophone2 [-c|-d] sourcefile [midifile]\n"); exit(1); } gramophone-0.8.13a/expcode.c0000644000175000017500000000570110757737531016126 0ustar giovannigiovanni/* * GRAMophone II, a grammar based algorithmic musical composition tool * -------------------------------------------------------------------- * * expcode.c * * Copyright (c) 2007, Giovanni Ferranti * * GRAMophone II is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ------------------------------------------------------------------- */ #include "global.h" extern char idTemp[]; unsigned int id; void gen_exp1_code(unsigned int op, unsigned int type1, unsigned int op1, unsigned int type2, unsigned int op2) { id=hash(idTemp, 0); players[playerCount]->productions[id]->exp->expcode[players[playerCount]-> productions[id]->ec][0]=op; players[playerCount]->productions[id]->exp->expcode[players[playerCount]-> productions[id]->ec][1]=type1; players[playerCount]->productions[id]->exp->expcode[players[playerCount]-> productions[id]->ec][2]=op1; players[playerCount]->productions[id]->exp->expcode[players[playerCount]-> productions[id]->ec][3]=type2; players[playerCount]->productions[id]->exp->expcode[players[playerCount]-> productions[id]->ec++][4]=op2; } void gen_exp2_code(unsigned int op, unsigned int op1, unsigned int type, unsigned int op2) { id=hash(idTemp, 0); players[playerCount]->productions[id]->exp->expcode[players[playerCount]-> productions[id]->ec][0]=op; players[playerCount]->productions[id]->exp->expcode[players[playerCount]-> productions[id]->ec][1]=op1; players[playerCount]->productions[id]->exp->expcode[players[playerCount]-> productions[id]->ec][2]=type; players[playerCount]->productions[id]->exp->expcode[players[playerCount]-> productions[id]->ec++][3]=op2; } void gen_exp3_code(unsigned int op, unsigned int type, unsigned int op1) { id=hash(idTemp, 0); players[playerCount]->productions[id]->exp->expcode[players[playerCount]-> productions[id]->ec][0]=op; players[playerCount]->productions[id]->exp->expcode[players[playerCount]-> productions[id]->ec][1]=type; players[playerCount]->productions[id]->exp->expcode[players[playerCount]-> productions[id]->ec++][2]=op1; } void gen_exp4_code(unsigned int op) { id=hash(idTemp, 0); players[playerCount]->productions[id]->exp->expcode[players[playerCount]-> productions[id]->ec++][0]=op; } gramophone-0.8.13a/global.h0000644000175000017500000001144311004322004015707 0ustar giovannigiovanni/* * GRAMophone II, a grammar based algorithmic musical composition tool * ------------------------------------------------------------------- * * global.h * * Copyright (c) 2007, Giovanni Ferranti * * GRAMophone II is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ------------------------------------------------------------------- */ #include #include #include #include "midifile.h" #define VERSION "0.8.13a" #define DEFAULT_FILENAME "composition.mid" #define MAX_FILENAME_LENGTH 256 #define MAX_ITERATIONS 50000 //numero massimo di iterazioni #define MAX_STR 4096 #define NUM_GLOBAL_PARAMS 7 #define NUM_LOCAL_PARAMS 6 #define NUM_VARS 1024 //numero massimo di variabili, sia globali //sia locali #define NUM_PLAYERS 128 //numero massimo di players #define NUM_CTRL 22 #define VAR_LENGTH 31 #define NUM_MACRO 65536 #define NUM_PRODS 1024 #define DIM_EXP 512 #define DIM_MIDI_CODE 1024 #define MAX_RECURSION 50 #define DIM_BUFFER 10240 #define MAX_CHORD 50 #define DIM_RTGD_BUFFER 256 /* * TEMP VARS */ char string_buf[MAX_STR], idTemp[MAX_STR]; unsigned int note[5], rest; unsigned int chord[MAX_CHORD][5]; /* * WORK VARS */ unsigned char isGlobal, globalWritten; unsigned int varCount, macroCount, playerCount, prev_duration, stringCount, level; /* * COMMAND LINE OPT */ FILE *midi; char namefile[MAX_FILENAME_LENGTH]; unsigned char checkOption, debugOption; /* * MIDI DATA */ char data[4]; /* * DATA STRUCTURES */ unsigned int global_resolution, global_iterations; unsigned char grammarOption; //1 - Chomsky; 2 - Lindenmayer char *strings[MAX_STR]; enum var_type {OCT=1, VEL, DUR, REL, BYTEDATA}; enum default_prm {DEFOCT, DEFVEL, DEFDUR, DEFREL, DEFINSTR, CHN, DEFMSB}; unsigned int global_params[NUM_GLOBAL_PARAMS]; //0 - Octave; 1 - Velocity //2 - Duration; 3 - Release //4 - Instrument; 5 - Channel; //6 - Msb unsigned char loc_par_flag[10]; //0 - grammar //1 - iterations //2 - time signature //3 - octave //4 - velocity //5 - duration //6 - release //7 - msb //8 - instrument //9 - channel //GrammyVM ASM enum GrammyAsm {_ADD=1, _SUB, _MUL, _DIV, _MOD, _INC, _DEC, _OR, _AND, _NOT, _EQ, _NE, _LT, _LE, _GT, _GE, _SP, _PRD, _PRD_ALT, _CHK, _ELSE, _GOTO, _EXP, _UPDATE, _ENDEXP, _MOV, _NOTEON, _REST, _EMPTY, _TRN, _INV, _RTRGD, _RTGINV, _RND, _ENDMELOP, _REP, _ENDREP, _CHORD, _ENDCHORD, _UMIN, _PRNT, _STR}; //Errors enum error_msg {UNTERMINATED_STR, EOF_ERR, TOO_DEEPLY, DISCOGRAPHY_NOT_FOUND, EXPECTED, MEMORY_ERR, ALREADY, GRAMMAR_EXPECTED, RES_OUT, IT_OUT, OUT, NUMERATOR_OUT, FRACTION_DEN_ERR, OCTAVE_OUT, TEMPO_OUT, PLAYER_EXPECTED, VAR_NOT_DECLARED, TOO_LONG, CHN_OUT, TOO_MANY_PLAYERS, TOO_MANY_VARS, TYPE_ERR, TOO_MANY_MACROS, TOO_MANY_NOTE_PAR, REPEAT_ERR, SILENT_ERR, TOO_MANY_STRINGS, ELSE_WITHOUT_CONDITION}; unsigned char glob_num, glob_den; char *title, *copyright; unsigned int tempo; typedef struct note_vars_value *pnote_var; typedef struct note_vars_value { char *name; unsigned char type; unsigned int value; } note_var; note_var global_vars[NUM_VARS]; typedef struct Expression *pExp; typedef struct Expression { unsigned int expcode[DIM_EXP][5]; } expression; typedef struct grammarProduction *pProd; typedef struct grammarProduction { char name[VAR_LENGTH]; unsigned int ec; //Expression Counter unsigned int cc; //Code Counter unsigned int numOr; unsigned int numOrAlt; unsigned char terminal; unsigned int idTerminal; pExp exp; unsigned int midicode[DIM_MIDI_CODE][10]; unsigned char created_by_body; unsigned int iterationCounter; unsigned char visited; } production; typedef struct virtual_player *pPlayer; typedef struct virtual_player { char *identifier; int local_params[NUM_LOCAL_PARAMS]; unsigned char num, den; unsigned char grammar; unsigned int iterations; note_var local_vars[NUM_VARS]; pProd productions[NUM_PRODS]; } player; pPlayer players[NUM_PLAYERS]; typedef struct macro_data *pmacro; typedef struct macro_data { char *name, *data; } macro; macro macros[NUM_MACRO]; gramophone-0.8.13a/grammyVM.c0000644000175000017500000023452011004322004016204 0ustar giovannigiovanni/* * GRAMophone II, a grammar based algorithmic musical composition tool * ------------------------------------------------------------------- * * grammyVM.c * * the GRAMophone II Virtual Machine * * Copyright (c) 2007, Giovanni Ferranti * * GRAMophone II is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ------------------------------------------------------------------- */ #include #include "global.h" typedef unsigned int retrograde_buffer[DIM_RTGD_BUFFER][8]; retrograde_buffer *rtgd_buffer[MAX_RECURSION]; char melop[MAX_RECURSION][2] /*0: OFF, 1: _TRN, 2: _INV, 3: _RTRGD , 4: _RTGINV*/; unsigned char op_counter=0, rtgd_counter=0, rtgd_note_count; void sort_attack(unsigned int chord[MAX_CHORD][5], int l, int r) { int i, j; unsigned int temp[5]; for(i=l; iproductions[id_prod]->ec=start; while((code=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][0])!=_ENDEXP) { switch(code) { case _AND: switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) { case 0: result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]; break; case 1: result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value; break; case 2: result1=result[j++]; } switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) { case 0: result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]; break; case 1: result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value; break; case 2: result2=result[j++]; } result[i++]=result1 && result2; break; case _OR: switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) { case 0: result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]; break; case 1: result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value; break; case 2: result1=result[j++]; } switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) { case 0: result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]; break; case 1: result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value; break; case 2: result2=result[j++]; } result[i++]=result1 || result2; break; case _NOT: switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) { case 0: result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]; break; case 1: result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value; break; case 2: result1=result[j++]; } result[i++]=!result1; break; case _EQ: switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) { case 0: result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]; break; case 1: result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value; break; case 2: result1=result[j++]; } switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) { case 0: result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]; break; case 1: result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value; break; case 2: result2=result[j++]; } result[i++]=result1==result2; break; case _NE: switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) { case 0: result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]; break; case 1: result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value; break; case 2: result1=result[j++]; } switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) { case 0: result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]; break; case 1: result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value; break; case 2: result2=result[j++]; } result[i++]=result1!=result2; break; case _LT: switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) { case 0: result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]; break; case 1: result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value; break; case 2: result1=result[j++]; } switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) { case 0: result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]; break; case 1: result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value; break; case 2: result2=result[j++]; } result[i++]=result1productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) { case 0: result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]; break; case 1: result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value; break; case 2: result1=result[j++]; } switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) { case 0: result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]; break; case 1: result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value; break; case 2: result2=result[j++]; } result[i++]=result1<=result2; break; case _GT: switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) { case 0: result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]; break; case 1: result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value; break; case 2: result1=result[j++]; } switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) { case 0: result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]; break; case 1: result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value; break; case 2: result2=result[j++]; } result[i++]=result1>result2; break; case _GE: switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) { case 0: result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]; break; case 1: result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value; break; case 2: result1=result[j++]; } switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) { case 0: result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]; break; case 1: result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value; break; case 2: result2=result[j++]; } result[i++]=result1>=result2; break; case _MOV: switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]) { case 0: players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].name? (result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].value=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]): (result1=global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].value=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]); break; case 1: players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].name? (result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].value=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]].value): (result1=global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].value=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]].value); break; case 2: players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].name? (result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].value=result[j++]): (result1=global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].value=result[j++]); } result[i++]=result1; break; case _ADD: switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) { case 0: result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]; break; case 1: result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value; break; case 2: result1=result[j++]; } switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) { case 0: result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]; break; case 1: result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value; break; case 2: result2=result[j++]; } result[i++]=result1+result2; break; case _SUB: switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) { case 0: result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]; break; case 1: result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value; break; case 2: result1=result[j++]; } switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) { case 0: result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]; break; case 1: result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value; break; case 2: result2=result[j++]; } result[i++]=result1-result2; break; case _MUL: switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) { case 0: result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]; break; case 1: result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value; break; case 2: result1=result[j++]; } switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) { case 0: result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]; break; case 1: result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value; break; case 2: result2=result[j++]; } result[i++]=result1*result2; break; case _DIV: switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) { case 0: result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]; break; case 1: result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value; break; case 2: result1=result[j++]; } switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) { case 0: result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]; break; case 1: result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value; break; case 2: result2=result[j++]; } result[i++]=result1/result2; break; case _MOD: switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) { case 0: result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]; break; case 1: result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value; break; case 2: result1=result[j++]; } switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][3]) { case 0: result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]; break; case 1: result2=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][4]].value; break; case 2: result2=result[j++]; } result[i++]=result1%result2; break; case _INC: result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].value; result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]; result[i++]=result1+result2; break; case _DEC: result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]].value; result2=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]; result[i++]=result1-result2; break; case _RND: switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) { case 0: result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]; break; case 1: result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value; break; case 2: result1=result[j++]; } result[i++]=rand()%result1; break; case _UMIN: switch(players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][1]) { case 0: result1=players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]; break; case 1: result1=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value:global_vars[players[playerCount]->productions[id_prod]->exp->expcode[players[playerCount]->productions[id_prod]->ec][2]].value; break; case 2: result1=result[j++]; } result[i++]=-result1; } if(players[playerCount]->productions[id_prod]->ec+1productions[id_prod]->ec++; } switch(type) { case OCT: if(result[i-1]<-2) result[i-1]=-2; if(result[i-1]>8) result[i-1]=8; break; case VEL: case REL: case BYTEDATA: if(result[i-1]<-127) result[i-1]=-127; if(result[i-1]>127) result[i-1]=127; break; case DUR: if(result[i-1]<0) result[i-1]=0; } return result[i-1]; } void process_rest(unsigned int id_prod, unsigned char isChord) { if(debugOption && !rtgd_counter) printf("rest parameters: "); switch(players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][1]) { case 0: rest=players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][2]; if(debugOption && !rtgd_counter) printf("%d\n", rest); //debug break; case 1: players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][2]].name?(rest=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][2]].value):(rest=global_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][2]].value); if(debugOption && !rtgd_counter) printf("%d\n", rest); //debug break; case _EXP: rest=calculate_expression(players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][2], id_prod, DUR); if(debugOption && !rtgd_counter) printf("%d\n", rest); //debug } } void process_note(unsigned int id_prod, unsigned char isChord) { int octave=0, sum_trn=0, sum_inv=0; register int i; unsigned int old_note, tmp; if(op_counter && players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][1]>=0) { old_note=note[0]=players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][1]; for(i=op_counter-1; i>=0; i--) switch(melop[i][0]) { case 1: sum_trn+=melop[i][1]; break; case 2: tmp=players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][1]+sum_inv+sum_trn; sum_inv+=2*(melop[i][1]-tmp); break; } note[0]+=sum_trn+sum_inv; while((int)note[0]<0) note[0]+=12; note[0]%=12; if(melop[op_counter-1][0]==1) octave=(sum_trn+old_note)/12; } else note[0]=players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][1]; if(debugOption && !rtgd_counter) printf("note: %d parameters: ", note[0]); //debug switch(players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][2]) { case 0: note[1]=players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][3]; note[1]+=octave; if((int)note[1]<-2) note[1]=-2; if((int)note[1]>8) note[1]=8; if(debugOption && !rtgd_counter) printf("%d ", note[1]); //debug break; case 1: if(players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][3]].name) { note[1]=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][3]].value; note[1]+=octave; if((int)note[1]<-2) note[1]=-2; if((int)note[1]>8) note[1]; if(debugOption && !rtgd_counter) printf("%d ", note[1]); //debug } else { note[1]=global_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][3]].value; note[1]+=octave; if((int)note[1]<-2) note[1]=-2; if((int)note[1]>8) note[1]=8; if(debugOption && !rtgd_counter) printf("%d ", note[1]); //debug } break; case _EXP: note[1]=calculate_expression(players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][3], id_prod, OCT); note[1]+=octave; if((int)note[1]<-2) note[1]=-2; if((int)note[1]>8) note[1]=8; if(debugOption && !rtgd_counter) printf("%d ", note[1]); //debug } switch(players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][4]) { case 0: note[2]=players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][5]; if(debugOption && !rtgd_counter) printf("%d ", note[2]); //debug break; case 1: players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][5]].name?(note[2]=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][5]].value):(note[2]=global_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][5]].value); if(debugOption && !rtgd_counter) printf("%d ", note[2]); //debug break; case _EXP: note[2]=calculate_expression(players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][5], id_prod, VEL); if(debugOption && !rtgd_counter) printf("%d ", note[2]); //debug } switch(players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][6]) { case 0: note[3]=players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][7]; if(debugOption && !rtgd_counter) printf("%d ", note[3]); //debug break; case 1: note[3]=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][7]].name?(note[3]=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][7]].value):(note[3]=global_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][7]].value); if(debugOption && !rtgd_counter) printf("%d ", note[3]); //debug break; case _EXP: note[3]=calculate_expression(players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][7], id_prod, DUR); if(debugOption && !rtgd_counter) printf("%d ", note[3]); //debug } switch(players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][8]) { case 0: note[4]=players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][9]; if(debugOption && !rtgd_counter) printf("%d\n", note[4]); //debug break; case 1: note[4]=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][9]].name?(note[4]=players[playerCount]->local_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][9]].value):(note[4]=global_vars[players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][9]].value); if(debugOption && !rtgd_counter) printf("%d\n", note[4]); //debug break; case _EXP: note[4]=calculate_expression(players[playerCount]->productions[id_prod]->midicode[players[playerCount]->productions[id_prod]->cc][9], id_prod, REL); if(debugOption && !rtgd_counter) printf("%d\n", note[4]); //debug } } unsigned char chomsky_generator(unsigned int nt, unsigned char isChord) { unsigned char code, rep[MAX_RECURSION][2]; unsigned int it, caso, casoAlt, reg, *pointer, tmp; register unsigned int i=0, j=0, k, w; register char note_chord_counter=0; int sum_trn=0, sum_inv=0, y; //(!players[playerCount]->productions[nt]->visited)?(players[playerCount]->productions[nt]->visited++):(players[playerCount]->productions[nt]->iterationCounter--); if(!players[playerCount]->productions[nt]->visited) players[playerCount]->productions[nt]->visited=++level; if(!players[playerCount]->productions[nt]->iterationCounter) { players[playerCount]->iterations?(players[playerCount]->productions[nt]->iterationCounter=players[playerCount]->iterations):(players[playerCount]->productions[nt]->iterationCounter=global_iterations); return 0; } players[playerCount]->productions[nt]->numOr>1?(caso=casual(players[playerCount]->productions[nt]->numOr)):(caso=1); players[playerCount]->productions[nt]->numOrAlt>1?(casoAlt=casual(players[playerCount]->productions[nt]->numOrAlt)):(casoAlt=1); if(debugOption && players[playerCount]->productions[nt]->numOr>1) printf("this is a non-deterministic production with %d alternatives. I choose: %d\n", players[playerCount]->productions[nt]->numOr, caso); //debug players[playerCount]->productions[nt]->cc=0; //printf("# of %s production: %d\n", players[playerCount]->productions[nt]->name, players[playerCount]->productions[nt]->numOr); //debug while(code=players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][0]) { switch(code) { case _PRD: if(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]!=caso) { if(players[playerCount]->productions[nt]->cc+1productions[nt]->cc++; else break; while(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][0]!=_PRD) { if(players[playerCount]->productions[nt]->cc+1productions[nt]->cc++; else break; } players[playerCount]->productions[nt]->cc--; } break; case _PRD_ALT: if(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]!=casoAlt) { if(players[playerCount]->productions[nt]->cc+1productions[nt]->cc++; else break; while(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][0]!=_PRD_ALT) { if(players[playerCount]->productions[nt]->cc+1productions[nt]->cc++; else break; } players[playerCount]->productions[nt]->cc--; } break; case _CHK: if(!calculate_expression(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1], nt, 0)) if(!players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]) return 1; else players[playerCount]->productions[nt]->cc=players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]-1; break; case _ELSE: return 0; case _GOTO: reg=players[playerCount]->productions[nt]->cc; if(players[playerCount]->productions[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]]->visited && players[playerCount]->productions[nt]->visited>=players[playerCount]->productions[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]]->visited) players[playerCount]->productions[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]]->iterationCounter--; chomsky_generator(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1], isChord); players[playerCount]->productions[nt]->cc=reg; break; case _NOTEON: process_note(nt, isChord); if(!rtgd_counter) { data[0]=note[0]+(12*(note[1]+2)); data[1]=note[2]; if(!isChord) { if(!mf_write_midi_event(prev_duration, note_on, players[playerCount]->local_params[CHN], data, 2)) { fprintf(stderr, "Error writing midi file!\n"); return -1; } data[1]=note[4]; if(!mf_write_midi_event(prev_duration=note[3], note_off, players[playerCount]->local_params[CHN], data, 2)) { fprintf(stderr, "Error writing midi file!\n"); return -1; } } else { chord[note_chord_counter][0]=note[0]+(12*(note[1]+2)); chord[note_chord_counter][1]=note[2]; chord[note_chord_counter][2]=note[3]; chord[note_chord_counter][3]=note[4]; chord[note_chord_counter++][4]=prev_duration; //rest associated with note in the chord } prev_duration=0; } else { if(!isChord) { (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][0]=0; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][1]=note[0]; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][2]=note[1]; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][3]=note[0]+(12*(note[1]+2)); (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][4]=note[2]; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][5]=note[3]; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count++][6]=note[4]; } else { (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][0]=_CHORD; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][1]=note[0]; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][2]=note[1]; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][3]=note[0]+(12*(note[1]+2)); (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][4]=note[2]; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][5]=note[3]; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][6]=note[4]; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count++][7]=prev_duration; prev_duration=0; } } break; case _EMPTY: process_note(nt, isChord); break; case _REST: process_rest(nt, isChord); if(!rtgd_counter) prev_duration=rest; else { (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][0]=_REST; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count++][1]=rest; if(isChord) prev_duration=rest; } break; case _TRN: melop[op_counter][0]=1; switch(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]) { case 0: melop[op_counter++][1]=players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]; break; case 1: melop[op_counter++][1]=players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value:global_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value; break; case _EXP: melop[op_counter++][1]=calculate_expression(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2], nt, BYTEDATA); } break; case _INV: pointer=players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc]; if((pointer+10)[0]!=_RTRGD) { melop[op_counter][0]=2; while(pointer[0]!=_NOTEON) pointer++; //step 10!!! melop[op_counter++][1]=pointer[1]; } else melop[op_counter++][0]=4; //Inversion of Retrograde break; case _RTRGD: melop[op_counter++][0]=3; rtgd_buffer[rtgd_counter++]=(retrograde_buffer *)malloc(DIM_RTGD_BUFFER*8*sizeof(unsigned int)); if(rtgd_counter>1) { (*rtgd_buffer[rtgd_counter-1])[0][0]=rtgd_note_count; rtgd_note_count=1; } else rtgd_note_count=0; break; case _ENDMELOP: if(melop[op_counter-1][0]==3) { if(melop[op_counter-2][0]==4) melop[op_counter-2][1]=(!(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count-1][0])?(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count-1][1]:(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count-2][1]; if(rtgd_counter>1) { w=(*rtgd_buffer[rtgd_counter-1])[0][0]; for(k=rtgd_note_count; k>1; k--) { /********************************************************/ if(melop[op_counter-2][0]==4) { (*rtgd_buffer[rtgd_counter-1])[k-1][1]+=2*(melop[op_counter-2][1]-(*rtgd_buffer[rtgd_counter-1])[k-1][1]); while((int)(*rtgd_buffer[rtgd_counter-1])[k-1][1]<0) (*rtgd_buffer[rtgd_counter-1])[k-1][1]+=12; (*rtgd_buffer[rtgd_counter-1])[k-1][1]%=12; (*rtgd_buffer[rtgd_counter-1])[k-1][3]=(*rtgd_buffer[rtgd_counter-1])[k-1][1]+(12*((*rtgd_buffer[rtgd_counter-1])[k-1][2]+2)); } /********************************************************/ (*rtgd_buffer[rtgd_counter-2])[w][0]=(*rtgd_buffer[rtgd_counter-1])[k-1][0]; (*rtgd_buffer[rtgd_counter-2])[w][1]=(*rtgd_buffer[rtgd_counter-1])[k-1][1]; (*rtgd_buffer[rtgd_counter-2])[w][2]=(*rtgd_buffer[rtgd_counter-1])[k-1][2]; (*rtgd_buffer[rtgd_counter-2])[w][3]=(*rtgd_buffer[rtgd_counter-1])[k-1][3]; (*rtgd_buffer[rtgd_counter-2])[w][4]=(*rtgd_buffer[rtgd_counter-1])[k-1][4]; (*rtgd_buffer[rtgd_counter-2])[w][5]=(*rtgd_buffer[rtgd_counter-1])[k-1][5]; (*rtgd_buffer[rtgd_counter-2])[w][6]=(*rtgd_buffer[rtgd_counter-1])[k-1][6]; (*rtgd_buffer[rtgd_counter-2])[w++][7]=(*rtgd_buffer[rtgd_counter-1])[k-1][7]; } rtgd_note_count=w; } else { for(k=rtgd_note_count; k>0; k--) switch((*rtgd_buffer[rtgd_counter-1])[k-1][0]) { case _CHORD: if(debugOption && !isChord) { printf("Playing a chord...\n"); //debug isChord=1; } /********************************************************/ if(melop[op_counter-2][0]==4) { (*rtgd_buffer[rtgd_counter-1])[k-1][1]+=2*(melop[op_counter-2][1]-(*rtgd_buffer[rtgd_counter-1])[k-1][1]); while((int)(*rtgd_buffer[rtgd_counter-1])[k-1][1]<0) (*rtgd_buffer[rtgd_counter-1])[k-1][1]+=12; (*rtgd_buffer[rtgd_counter-1])[k-1][1]%=12; (*rtgd_buffer[rtgd_counter-1])[k-1][3]=(*rtgd_buffer[rtgd_counter-1])[k-1][1]+(12*((*rtgd_buffer[rtgd_counter-1])[k-1][2]+2)); } /********************************************************/ chord[note_chord_counter][0]=(*rtgd_buffer[rtgd_counter-1])[k-1][3]; chord[note_chord_counter][1]=(*rtgd_buffer[rtgd_counter-1])[k-1][4]; chord[note_chord_counter][2]=(*rtgd_buffer[rtgd_counter-1])[k-1][5]; chord[note_chord_counter][3]=(*rtgd_buffer[rtgd_counter-1])[k-1][6]; chord[note_chord_counter++][4]=(*rtgd_buffer[rtgd_counter-1])[k-1][7]; //rest associated with note in the chord if(debugOption) printf("note: %d parameters: %d %d %d %d\n", (*rtgd_buffer[rtgd_counter-1])[k-1][1], (*rtgd_buffer[rtgd_counter-1])[k-1][2], (*rtgd_buffer[rtgd_counter-1])[k-1][4], (*rtgd_buffer[rtgd_counter-1])[k-1][5], (*rtgd_buffer[rtgd_counter-1])[k-1][6]); //debug break; case _ENDCHORD: if(!isChord) break; isChord=0; if(debugOption) printf("Chord ended\n"); //debug sort_attack(chord, 0, --note_chord_counter); for(w=0; w<=note_chord_counter; w++) { data[0]=chord[w][0]; data[1]=chord[w][1]; if(!mf_write_midi_event(chord[w][4], note_on, players[playerCount]->local_params[CHN], data, 2)) { fprintf(stderr, "Error writing midi file!\n"); return -1; } } sort_duration(chord, 0, note_chord_counter); data[0]=chord[0][0]; data[1]=chord[0][3]; if(!mf_write_midi_event(chord[0][2], note_off, players[playerCount]->local_params[CHN], data, 2)) { fprintf(stderr, "Error writing midi file!\n"); return -1; } for(w=1; w<=note_chord_counter; w++) { data[0]=chord[w][0]; data[1]=chord[w][3]; if(!mf_write_midi_event((chord[w][2]+chord[w][4])-(chord[w-1][2]+chord[w-1][4]), note_off, players[playerCount]->local_params[CHN], data, 2)) { fprintf(stderr, "Error writing midi file!\n"); return -1; } } note_chord_counter=0; break; case _REST: prev_duration=(*rtgd_buffer[rtgd_counter-1])[k-1][1]; if(debugOption) printf("rest parameters: %d\n", (*rtgd_buffer[rtgd_counter-1])[k-1][1]); break; default: /********************************************************/ if(melop[op_counter-2][0]==4) { (*rtgd_buffer[rtgd_counter-1])[k-1][1]+=2*(melop[op_counter-2][1]-(*rtgd_buffer[rtgd_counter-1])[k-1][1]); while((int)(*rtgd_buffer[rtgd_counter-1])[k-1][1]<0) (*rtgd_buffer[rtgd_counter-1])[k-1][1]+=12; (*rtgd_buffer[rtgd_counter-1])[k-1][1]%=12; (*rtgd_buffer[rtgd_counter-1])[k-1][3]=(*rtgd_buffer[rtgd_counter-1])[k-1][1]+(12*((*rtgd_buffer[rtgd_counter-1])[k-1][2]+2)); } /********************************************************/ data[0]=(*rtgd_buffer[rtgd_counter-1])[k-1][3]; data[1]=(*rtgd_buffer[rtgd_counter-1])[k-1][4]; if(!mf_write_midi_event(prev_duration, note_on, players[playerCount]->local_params[CHN], data, 2)) { fprintf(stderr, "Error writing midi file!\n"); return -1; } data[1]=(*rtgd_buffer[rtgd_counter-1])[k-1][6]; if(!mf_write_midi_event(prev_duration=(*rtgd_buffer[rtgd_counter-1])[k-1][5], note_off, players[playerCount]->local_params[CHN], data, 2)) { fprintf(stderr, "Error writing midi file!\n"); return -1; } if(debugOption) printf("note: %d parameters: %d %d %d %d\n", (*rtgd_buffer[rtgd_counter-1])[k-1][1], (*rtgd_buffer[rtgd_counter-1])[k-1][2], (*rtgd_buffer[rtgd_counter-1])[k-1][4], (*rtgd_buffer[rtgd_counter-1])[k-1][5], (*rtgd_buffer[rtgd_counter-1])[k-1][6]); //debug prev_duration=0; } } free(rtgd_buffer[rtgd_counter-1]); rtgd_counter--; } melop[op_counter-1][0]=melop[op_counter-1][1]=0; op_counter--; break; case _UPDATE: calculate_expression(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1], nt, players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]); break; case _REP: rep[i][0]=players[playerCount]->productions[nt]->cc+1; switch(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]) { case 0: rep[i++][1]=players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]; break; case 1: rep[i++][1]=players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value:global_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value; break; case _EXP: rep[i++][1]=calculate_expression(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2], nt, BYTEDATA); } if(!rep[i-1][1]) { j++; while(j) { if(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][0]==_REP) j++; if(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][0]==_ENDREP) j--; if(players[playerCount]->productions[nt]->cc+1productions[nt]->cc++; else break; } } break; case _ENDREP: if(rep[i-1][1]-1) { players[playerCount]->productions[nt]->cc=rep[i-1][0]; rep[i-1][1]--; continue; } else i--; break; case _CHORD: if(debugOption && !rtgd_counter) printf("Playing a chord...\n"); //debug else (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count++][0]=_ENDCHORD; isChord=1; break; case _ENDCHORD: if(debugOption && !rtgd_counter) printf("Chord ended\n"); //debug isChord=0; if(!rtgd_counter) { sort_attack(chord, 0, --note_chord_counter); for(k=0; k<=note_chord_counter; k++) { data[0]=chord[k][0]; data[1]=chord[k][1]; if(!mf_write_midi_event(chord[k][4], note_on, players[playerCount]->local_params[CHN], data, 2)) { fprintf(stderr, "Error writing midi file!\n"); return -1; } } sort_duration(chord, 0, note_chord_counter); data[0]=chord[0][0]; data[1]=chord[0][3]; if(!mf_write_midi_event(chord[0][2], note_off, players[playerCount]->local_params[CHN], data, 2)) { fprintf(stderr, "Error writing midi file!\n"); return -1; } for(k=1; k<=note_chord_counter; k++) { data[0]=chord[k][0]; data[1]=chord[k][3]; if(!mf_write_midi_event((chord[k][2]+chord[k][4])-(chord[k-1][2]+chord[k-1][4]), note_off, players[playerCount]->local_params[CHN], data, 2)) { fprintf(stderr, "Error writing midi file!\n"); return -1; } } note_chord_counter=0; } else (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count++][0]=_ENDCHORD; break; case _PRNT: switch(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]) { case 0: printf("%d", players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]); break; case 1: printf("%d", players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value:global_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value); break; case _EXP: printf("%d", calculate_expression(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2], nt, players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][3])); break; case _STR: printf("%s", strings[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]]); } } if(players[playerCount]->productions[nt]->cc+1productions[nt]->cc++; else break; } if(players[playerCount]->iterations) { if(players[playerCount]->productions[nt]->iterationCounteriterations) players[playerCount]->productions[nt]->iterationCounter=players[playerCount]->iterations; } else if(players[playerCount]->productions[nt]->iterationCounterproductions[nt]->iterationCounter=global_iterations; return 0; } unsigned char lindenmayer_prod_generator(unsigned int nt, unsigned int *buffer) { unsigned char code, rep[MAX_RECURSION][2], isChord=0; unsigned int caso, casoAlt, *pointer, tmp; char string_buf[MAX_STR], str_temp_buf[MAX_STR]; register unsigned int i=0, j=0, k, w, counter=0; register char note_chord_counter=0; int sum_trn=0, sum_inv=0, y; memset(melop, 0, 2*MAX_RECURSION); players[playerCount]->productions[nt]->numOr>1?(caso=casual(players[playerCount]->productions[nt]->numOr)):(caso=1); players[playerCount]->productions[nt]->numOrAlt>1?(caso=casual(players[playerCount]->productions[nt]->numOrAlt)):(casoAlt=1); if(debugOption && players[playerCount]->productions[nt]->numOr>1) printf("this is a non-deterministic production with %d alternatives. I choose: %d\n", players[playerCount]->productions[nt]->numOr, caso); //debug players[playerCount]->productions[nt]->cc=0; while(code=players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][0]) { switch(code) { case _PRD: if(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]!=caso) { if(players[playerCount]->productions[nt]->cc+1productions[nt]->cc++; else break; while(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][0]!=_PRD) { if(players[playerCount]->productions[nt]->cc+1productions[nt]->cc++; else break; } players[playerCount]->productions[nt]->cc--; } break; case _PRD_ALT: if(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]!=casoAlt) { if(players[playerCount]->productions[nt]->cc+1productions[nt]->cc++; else break; while(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][0]!=_PRD_ALT) { if(players[playerCount]->productions[nt]->cc+1productions[nt]->cc++; else break; } players[playerCount]->productions[nt]->cc--; } break; case _CHK: if(!calculate_expression(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1], nt, 0)) if(!players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]) return 0; else players[playerCount]->productions[nt]->cc=players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]-1; break; case _ELSE: return 0; case _NOTEON: process_note(nt, isChord); if(!rtgd_counter) { data[0]=note[0]+(12*(note[1]+2)); data[1]=note[2]; if(!isChord) { if(!mf_write_midi_event(prev_duration, note_on, players[playerCount]->local_params[CHN], data, 2)) { fprintf(stderr, "Error writing midi file!\n"); return -1; } data[1]=note[4]; if(!mf_write_midi_event(prev_duration=note[3], note_off, players[playerCount]->local_params[CHN], data, 2)) { fprintf(stderr, "Error writing midi file!\n"); return -1; } sprintf(string_buf, "%d%d%d%d%d", note[0], note[1], note[2], note[3], note[4]); buffer[counter++]=hash(string_buf, 0); } else { chord[note_chord_counter][0]=note[0]+(12*(note[1]+2)); chord[note_chord_counter][1]=note[2]; chord[note_chord_counter][2]=note[3]; chord[note_chord_counter][3]=note[4]; chord[note_chord_counter++][4]=prev_duration; //rest associated with note in the chord sprintf(str_temp_buf, "%d%d%d%d%d", note[0], note[1], note[2], note[3], note[4]); strcat(string_buf, str_temp_buf); } prev_duration=0; } else { if(!isChord) { (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][0]=0; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][1]=note[0]; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][2]=note[1]; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][3]=note[0]+(12*(note[1]+2)); (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][4]=note[2]; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][5]=note[3]; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count++][6]=note[4]; } else { (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][0]=_CHORD; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][1]=note[0]; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][2]=note[1]; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][3]=note[0]+(12*(note[1]+2)); (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][4]=note[2]; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][5]=note[3]; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][6]=note[4]; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count++][7]=prev_duration; sprintf(str_temp_buf, "%d%d%d%d%d", note[0], note[1], note[2], note[3], note[4]); strcat(string_buf, str_temp_buf); prev_duration=0; } } break; case _EMPTY: process_note(nt, isChord); break; case _REST: process_rest(nt, isChord); if(!rtgd_counter) prev_duration=rest; else { (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count][0]=_REST; (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count++][1]=rest; } if(!isChord) { sprintf(string_buf, "%d", rest); buffer[counter++]=hash(string_buf, 0); } else { sprintf(str_temp_buf, "%d", rest); strcat(string_buf, str_temp_buf); if(rtgd_counter) prev_duration=rest; } break; case _TRN: melop[op_counter][0]=1; switch(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]) { case 0: melop[op_counter++][1]=players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]; break; case 1: melop[op_counter++][1]=players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value:global_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value; break; case _EXP: melop[op_counter++][1]=calculate_expression(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2], nt, BYTEDATA); } break; case _INV: pointer=players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc]; if((pointer+10)[0]!=_RTRGD) { melop[op_counter][0]=2; while(pointer[0]!=_NOTEON) pointer++; melop[op_counter++][1]=pointer[1]; } else melop[op_counter++][0]=4; //Inversion of Retrograde break; case _RTRGD: melop[op_counter++][0]=3; rtgd_buffer[rtgd_counter++]=(retrograde_buffer *)malloc(DIM_RTGD_BUFFER*8*sizeof(unsigned int)); if(rtgd_counter>1) { (*rtgd_buffer[rtgd_counter-1])[0][0]=rtgd_note_count; rtgd_note_count=1; } else rtgd_note_count=0; break; case _ENDMELOP: if(melop[op_counter-1][0]==3) { if(melop[op_counter-2][0]==4) melop[op_counter-2][1]=(!(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count-1][0])?(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count-1][1]:(*rtgd_buffer[rtgd_counter-1])[rtgd_note_count-2][1]; if(rtgd_counter>1) { w=(*rtgd_buffer[rtgd_counter-1])[0][0]; for(k=rtgd_note_count; k>1; k--) { /********************************************************/ if(melop[op_counter-2][0]==4) { (*rtgd_buffer[rtgd_counter-1])[k-1][1]+=2*(melop[op_counter-2][1]-(*rtgd_buffer[rtgd_counter-1])[k-1][1]); while((int)(*rtgd_buffer[rtgd_counter-1])[k-1][1]<0) (*rtgd_buffer[rtgd_counter-1])[k-1][1]+=12; (*rtgd_buffer[rtgd_counter-1])[k-1][1]%=12; (*rtgd_buffer[rtgd_counter-1])[k-1][3]=(*rtgd_buffer[rtgd_counter-1])[k-1][1]+(12*((*rtgd_buffer[rtgd_counter-1])[k-1][2]+2)); } /********************************************************/ (*rtgd_buffer[rtgd_counter-2])[w][0]=(*rtgd_buffer[rtgd_counter-1])[k-1][0]; (*rtgd_buffer[rtgd_counter-2])[w][1]=(*rtgd_buffer[rtgd_counter-1])[k-1][1]; (*rtgd_buffer[rtgd_counter-2])[w][2]=(*rtgd_buffer[rtgd_counter-1])[k-1][2]; (*rtgd_buffer[rtgd_counter-2])[w][3]=(*rtgd_buffer[rtgd_counter-1])[k-1][3]; (*rtgd_buffer[rtgd_counter-2])[w][4]=(*rtgd_buffer[rtgd_counter-1])[k-1][4]; (*rtgd_buffer[rtgd_counter-2])[w][5]=(*rtgd_buffer[rtgd_counter-1])[k-1][5]; (*rtgd_buffer[rtgd_counter-2])[w][6]=(*rtgd_buffer[rtgd_counter-1])[k-1][6]; (*rtgd_buffer[rtgd_counter-2])[w++][7]=(*rtgd_buffer[rtgd_counter-1])[k-1][7]; } rtgd_note_count=w; } else { for(k=rtgd_note_count; k>0; k--) switch((*rtgd_buffer[rtgd_counter-1])[k-1][0]) { case _CHORD: if(debugOption && !isChord) { printf("Playing a chord...\n"); //debug isChord=1; } /********************************************************/ if(melop[op_counter-2][0]==4) { (*rtgd_buffer[rtgd_counter-1])[k-1][1]+=2*(melop[op_counter-2][1]-(*rtgd_buffer[rtgd_counter-1])[k-1][1]); while((int)(*rtgd_buffer[rtgd_counter-1])[k-1][1]<0) (*rtgd_buffer[rtgd_counter-1])[k-1][1]+=12; (*rtgd_buffer[rtgd_counter-1])[k-1][1]%=12; (*rtgd_buffer[rtgd_counter-1])[k-1][3]=(*rtgd_buffer[rtgd_counter-1])[k-1][1]+(12*((*rtgd_buffer[rtgd_counter-1])[k-1][2]+2)); } /********************************************************/ chord[note_chord_counter][0]=(*rtgd_buffer[rtgd_counter-1])[k-1][3]; chord[note_chord_counter][1]=(*rtgd_buffer[rtgd_counter-1])[k-1][4]; chord[note_chord_counter][2]=(*rtgd_buffer[rtgd_counter-1])[k-1][5]; chord[note_chord_counter][3]=(*rtgd_buffer[rtgd_counter-1])[k-1][6]; chord[note_chord_counter++][4]=(*rtgd_buffer[rtgd_counter-1])[k-1][7]; //rest associated with note in the chord if(debugOption) printf("note: %d parameters: %d %d %d %d\n", (*rtgd_buffer[rtgd_counter-1])[k-1][1], (*rtgd_buffer[rtgd_counter-1])[k-1][2], (*rtgd_buffer[rtgd_counter-1])[k-1][4], (*rtgd_buffer[rtgd_counter-1])[k-1][5], (*rtgd_buffer[rtgd_counter-1])[k-1][6]); //debug break; case _ENDCHORD: if(!isChord) break; isChord=0; if(debugOption) printf("Chord ended\n"); //debug //buffer[counter++]=hash(string_buf, 0); sort_attack(chord, 0, --note_chord_counter); for(w=0; w<=note_chord_counter; w++) { data[0]=chord[w][0]; data[1]=chord[w][1]; if(!mf_write_midi_event(chord[w][4], note_on, players[playerCount]->local_params[CHN], data, 2)) { fprintf(stderr, "Error writing midi file!\n"); return -1; } } sort_duration(chord, 0, note_chord_counter); data[0]=chord[0][0]; data[1]=chord[0][3]; if(!mf_write_midi_event(chord[0][2], note_off, players[playerCount]->local_params[CHN], data, 2)) { fprintf(stderr, "Error writing midi file!\n"); return -1; } for(w=1; w<=note_chord_counter; w++) { data[0]=chord[w][0]; data[1]=chord[w][3]; if(!mf_write_midi_event((chord[w][2]+chord[w][4])-(chord[w-1][2]+chord[w-1][4]), note_off, players[playerCount]->local_params[CHN], data, 2)) { fprintf(stderr, "Error writing midi file!\n"); return -1; } } note_chord_counter=0; break; case _REST: /*if(!isChord) { sprintf(string_buf, "%d", (*rtgd_buffer[rtgd_counter-1])[k-1][1]); buffer[counter++]=hash(string_buf, 0); } else { sprintf(str_temp_buf, "%d", (*rtgd_buffer[rtgd_counter-1])[k-1][1]); strcat(string_buf, str_temp_buf); }*/ prev_duration=rest; if(debugOption) printf("rest parameters: %d\n", (*rtgd_buffer[rtgd_counter-1])[k-1][1]); break; default: /********************************************************/ if(melop[op_counter-2][0]==4) { (*rtgd_buffer[rtgd_counter-1])[k-1][1]+=2*(melop[op_counter-2][1]-(*rtgd_buffer[rtgd_counter-1])[k-1][1]); while((int)(*rtgd_buffer[rtgd_counter-1])[k-1][1]<0) (*rtgd_buffer[rtgd_counter-1])[k-1][1]+=12; (*rtgd_buffer[rtgd_counter-1])[k-1][1]%=12; (*rtgd_buffer[rtgd_counter-1])[k-1][3]=(*rtgd_buffer[rtgd_counter-1])[k-1][1]+(12*((*rtgd_buffer[rtgd_counter-1])[k-1][2]+2)); } /********************************************************/ data[0]=(*rtgd_buffer[rtgd_counter-1])[k-1][3]; data[1]=(*rtgd_buffer[rtgd_counter-1])[k-1][4]; if(!mf_write_midi_event(prev_duration, note_on, players[playerCount]->local_params[CHN], data, 2)) { fprintf(stderr, "Error writing midi file!\n"); return -1; } data[1]=(*rtgd_buffer[rtgd_counter-1])[k-1][6]; if(!mf_write_midi_event(prev_duration=(*rtgd_buffer[rtgd_counter-1])[k-1][5], note_off, players[playerCount]->local_params[CHN], data, 2)) { fprintf(stderr, "Error writing midi file!\n"); return -1; } sprintf(string_buf, "%d%d%d%d%d", (*rtgd_buffer[rtgd_counter-1])[k-1][1], (*rtgd_buffer[rtgd_counter-1])[k-1][2], (*rtgd_buffer[rtgd_counter-1])[k-1][4], (*rtgd_buffer[rtgd_counter-1])[k-1][5], (*rtgd_buffer[rtgd_counter-1])[k-1][6]); buffer[counter++]=hash(string_buf, 0); if(debugOption) printf("note: %d parameters: %d %d %d %d\n", (*rtgd_buffer[rtgd_counter-1])[k-1][1], (*rtgd_buffer[rtgd_counter-1])[k-1][2], (*rtgd_buffer[rtgd_counter-1])[k-1][4], (*rtgd_buffer[rtgd_counter-1])[k-1][5], (*rtgd_buffer[rtgd_counter-1])[k-1][6]); //debug prev_duration=0; } } free(rtgd_buffer[rtgd_counter-1]); rtgd_counter--; } melop[op_counter-1][0]=melop[op_counter-1][1]=0; op_counter--; break; case _UPDATE: calculate_expression(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1], nt, players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]); break; case _REP: rep[i][0]=players[playerCount]->productions[nt]->cc+1; switch(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]) { case 0: rep[i++][1]=players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]; break; case 1: rep[i++][1]=players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value:global_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value; break; case _EXP: rep[i++][1]=calculate_expression(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2], nt, BYTEDATA); } if(!rep[i-1][1]) { j++; while(j) { if(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][0]==_REP) j++; if(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][0]==_ENDREP) j--; if(players[playerCount]->productions[nt]->cc+1productions[nt]->cc++; else break; } } break; case _ENDREP: if(rep[i-1][1]-1) { players[playerCount]->productions[nt]->cc=rep[i-1][0]; rep[i-1][1]--; continue; } else i--; break; case _CHORD: if(debugOption && !rtgd_counter) printf("Playing a chord...\n"); //debug else (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count++][0]=_ENDCHORD; isChord=1; strcpy(string_buf, ""); break; case _ENDCHORD: if(debugOption && !rtgd_counter) printf("Chord ended\n"); //debug isChord=0; buffer[counter++]=hash(string_buf, 0); if(!rtgd_counter) { sort_attack(chord, 0, --note_chord_counter); for(k=0; k<=note_chord_counter; k++) { data[0]=chord[k][0]; data[1]=chord[k][1]; if(!mf_write_midi_event(chord[k][4], note_on, players[playerCount]->local_params[CHN], data, 2)) { fprintf(stderr, "Error writing midi file!\n"); return -1; } } sort_duration(chord, 0, note_chord_counter); data[0]=chord[0][0]; data[1]=chord[0][3]; if(!mf_write_midi_event(chord[0][2], note_off, players[playerCount]->local_params[CHN], data, 2)) { fprintf(stderr, "Error writing midi file!\n"); return -1; } for(k=1; k<=note_chord_counter; k++) { data[0]=chord[k][0]; data[1]=chord[k][3]; if(!mf_write_midi_event((chord[k][2]+chord[k][4])-(chord[k-1][2]+chord[k-1][4]), note_off, players[playerCount]->local_params[CHN], data, 2)) { fprintf(stderr, "Error writing midi file!\n"); return -1; } } note_chord_counter=0; } else (*rtgd_buffer[rtgd_counter-1])[rtgd_note_count++][0]=_ENDCHORD; break; case _PRNT: switch(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][1]) { case 0: printf("%d", players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]); break; case 1: printf("%d", players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].name?players[playerCount]->local_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value:global_vars[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]].value); break; case _EXP: printf("%d", calculate_expression(players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2], nt, players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][3])); break; case _STR: printf("%s", strings[players[playerCount]->productions[nt]->midicode[players[playerCount]->productions[nt]->cc][2]]); } } if(players[playerCount]->productions[nt]->cc+1productions[nt]->cc++; else break; } return 0; } void lindenmayer_generator(unsigned int nt, unsigned int iteration) { unsigned int buffer[DIM_BUFFER], supporto[DIM_BUFFER], *pointerToBuffer; register unsigned int i, j; memset(supporto, 0, DIM_BUFFER); lindenmayer_prod_generator(nt, supporto); for(i=1; iproductions[nt]) { lindenmayer_prod_generator(nt, pointerToBuffer); while(*pointerToBuffer) pointerToBuffer++; } memset(supporto, 0, DIM_BUFFER); memcpy(supporto, buffer, DIM_BUFFER); memset(buffer, 0, DIM_BUFFER); } } int myputc(c) { return putc(c, midi); } int write_player_track(track) { register unsigned int iteration; playerCount = track; memset(melop, 0, MAX_RECURSION*2); if(!globalWritten) { if(!mf_write_meta_event(0, copyright_notice, copyright, strlen(copyright))) { fprintf(stderr, "Error writing midi file!\n"); return -1; } mf_write_tempo((long)60000000/tempo); globalWritten++; } prev_duration=0; if(!debugOption) printf("Player %s is generating...\n", players[playerCount]->identifier); players[playerCount]->num?(data[0]=players[playerCount]->num):(data[0]=glob_num); players[playerCount]->den?(data[1]=log10(players[playerCount]->den)/log10(2)):(data[1]=log10(glob_den)/log10(2)); data[2]=24; data[3]=8; if(!mf_write_meta_event(0, time_signature, data, 4)) { fprintf(stderr, "Error writing midi file!\n"); return -1; } players[playerCount]->local_params[DEFINSTR]?(data[0]=players[playerCount]->local_params[DEFINSTR]):(data[0]=global_params[DEFINSTR]); if(!mf_write_midi_event(0, program_chng, players[playerCount]->local_params[CHN], data, 1)) { fprintf(stderr, "Error writing midi file!\n"); return -1; } players[playerCount]->iterations?(iteration=players[playerCount]->iterations):(iteration=global_iterations); switch(players[playerCount]->grammar) { case 1: if(debugOption) print_local_params(playerCount); //debug chomsky_generator(hash("@composition", 0), 0); break; case 2: if(debugOption) print_local_params(playerCount); //debug lindenmayer_generator(hash("axiom", 0), iteration); break; default: if(debugOption) print_local_params(playerCount); //debug switch(grammarOption) { case 1: chomsky_generator(hash("@composition", 0), 0); break; case 2: lindenmayer_generator(hash("axiom", 0), iteration); } } if(!debugOption) printf("\n...ok\n"); return 1; } int grammyvm() { unsigned int ntracks; if(!strcmp(namefile, "")) strcpy(namefile, DEFAULT_FILENAME); if(!(midi=fopen(namefile, "w"))) { fprintf(stderr, "Error writing midi file!\n"); exit(1); } if(debugOption) { print_composition_info(); //debug print_global_params(); //debug } Mf_putc=myputc; Mf_writetrack=write_player_track; mfwrite(0, playerCount, global_resolution, midi); if(!debugOption) printf("midi file succesfully generated!\n"); } gramophone-0.8.13a/hash.c0000644000175000017500000001475110757737531015427 0ustar giovannigiovanni/* * GRAMophone II, a grammar based algorithmic musical composition tool * -------------------------------------------------------------------- * * hash.c * * Copyright (c) 2007, Giovanni Ferranti * * GRAMophone II is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ------------------------------------------------------------------- */ // Funzione di Hash unversale. Viene utilizzata per calcolare gli // indici nelle tabelle dei simboli #include #include "global.h" #define A 31415 #define B 27183 #define C 97 unsigned M=NUM_VARS; extern int ctrl[]; unsigned int hashU(char *v) { unsigned int h, a=A; for(h=0; *v!='\0'; v++, a=a*B%(M-1)) h=(a*h+*v)%M; return h; } unsigned char hashTwo(char *v) { return (*v%C)+1; } //sentinel: //0 - local variables //1 - global variables //2 - macros //3 - memory allocation for a single production void dhInsert(pnote_var noteVar, char *text, unsigned char sentinel, unsigned char created_by_body) { unsigned int i; unsigned char k; switch(sentinel) { case 1: i=hashU(noteVar->name); k=hashTwo(noteVar->name); while(global_vars[i].name!=NULL) { if(!strcmp(global_vars[i].name, noteVar->name)) sntx_err(ALREADY, "variable "); i=(i+k)%M; } if(!(global_vars[i].name=(char *)malloc((1+VAR_LENGTH)*sizeof(char)))) sntx_err(MEMORY_ERR, ""); strcpy(global_vars[i].name, noteVar->name); global_vars[i].type=noteVar->type; global_vars[i].value=noteVar->value; break; case 0: i=hashU(noteVar->name); k=hashTwo(noteVar->name); while(players[playerCount]->local_vars[i].name!=NULL) { if(!strcmp(players[playerCount]->local_vars[i].name, noteVar->name)) sntx_err(ALREADY, "variable "); i=(i+k)%M; } if(!(players[playerCount]->local_vars[i].name=(char *) malloc((1+VAR_LENGTH)*sizeof(char)))) sntx_err(MEMORY_ERR, ""); strcpy(players[playerCount]->local_vars[i].name, noteVar->name); players[playerCount]->local_vars[i].type=noteVar->type; players[playerCount]->local_vars[i].value=noteVar->value; break; case 2: i=hashU(text); k=hashTwo(text); while(macros[i].name!=NULL) i=(i+k)%M; if(!(macros[i].name=(char *)malloc((1+VAR_LENGTH)*sizeof(char)))) sntx_err(MEMORY_ERR, ""); strcpy(macros[i].name, text); if(!(macros[i].data=(char *)malloc((1+strlen(string_buf))*sizeof(char)))) sntx_err(MEMORY_ERR, ""); strcpy(macros[i].data, string_buf); break; case 3: i=hashU(text); k=hashU(text); while((players[playerCount]->productions[i])!=NULL) { if(!strcmp(players[playerCount]->productions[i]->name, text)) { if(players[playerCount]->productions[i]->created_by_body) { players[playerCount]->productions[i]->created_by_body=0; return; } else { gen_code(_PRD, ++players[playerCount]->productions[i]->numOr); return; } } i=(i+k)%M; } if(!(players[playerCount]->productions[i]=(pProd)malloc(sizeof(production)))) sntx_err(MEMORY_ERR, ""); strcpy(players[playerCount]->productions[i]->name, text); players[playerCount]->productions[i]->ec= players[playerCount]->productions[i]->cc= players[playerCount]->productions[i]->terminal= players[playerCount]->productions[i]->idTerminal= players[playerCount]->productions[i]->visited=0; players[playerCount]->iterations?(players[playerCount]->productions[i]->iterationCounter=players[playerCount]->iterations):(players[playerCount]->productions[i]->iterationCounter=global_iterations); created_by_body==1?(players[playerCount]->productions[i]->created_by_body=1):(players[playerCount]->productions[i]->created_by_body=0); players[playerCount]->productions[i]->numOr=players[playerCount]->productions[i]->numOrAlt=1; players[playerCount]->productions[i]->exp=NULL; memset(players[playerCount]->productions[i]->midicode, 0, 10*DIM_MIDI_CODE); break; } } pnote_var dhSearch(char *v, unsigned char sentinel) { unsigned int i=hashU(v); unsigned char k=hashTwo(v); switch(sentinel) { case 1: while(global_vars[i].name!=NULL) if(!strcmp(global_vars[i].name, v)) return &global_vars[i]; else i=(i+k)%M; return NULL; case 0: while(players[playerCount]->local_vars[i].name!=NULL) if(!strcmp(players[playerCount]->local_vars[i].name, v)) return &players[playerCount]->local_vars[i]; else i=(i+k)%M; return NULL; } } //search for macros char *dhSearch2(char *v) { unsigned int i=hashU(v); unsigned char k=hashTwo(v); while(macros[i].name!=NULL) if(!strcmp(macros[i].name, v)) return macros[i].data; else i=(i+k)%M; return '\0'; } unsigned int hash(char *v, unsigned char sentinel) { unsigned int i=hashU(v); unsigned char k=hashTwo(v); switch(sentinel) { case 0: while(players[playerCount]->productions[i]!=NULL) if(!strcmp(players[playerCount]->productions[i]->name, v)) return i; else i=(i+k)%M; break; case 1: while(players[playerCount]->local_vars[i].name!=NULL) if(!strcmp(players[playerCount]->local_vars[i].name, v)) { if(!ctrl[3]) ctrl[3]=players[playerCount]->local_vars[i].type; else if(players[playerCount]->local_vars[i].type!=ctrl[3]) sntx_err(TYPE_ERR, ""); return i; } else i=(i+k)%M; while(global_vars[i].name!=NULL) if(!strcmp(global_vars[i].name, v)) { if(!ctrl[3]) ctrl[3]=global_vars[i].type; else if(global_vars[i].type!=ctrl[3]) sntx_err(TYPE_ERR, ""); return i; } else i=(i+k)%M; sntx_err(VAR_NOT_DECLARED, ""); break; } } gramophone-0.8.13a/init.c0000644000175000017500000000652010757737531015442 0ustar giovannigiovanni/* * GRAMophone II, a grammar based algorithmic musical composition tool * -------------------------------------------------------------------- * * init.c * * Copyright (c) 2007, Giovanni Ferranti * * GRAMophone II is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ------------------------------------------------------------------- */ #include "global.h" #include void init_rand(void) { int stime; long ltime; ltime=time(NULL); stime=(unsigned)ltime/2; srand(stime); } void init_local_flag(void) { memset(loc_par_flag, 0, 10); } void initGRAMophone(void) { register unsigned int i; extern int ctrl[]; extern pnote_var noteVarTemp, noteVarTempBis; varCount=macroCount=stringCount=globalWritten=0; isGlobal=1; tempo=120; global_iterations=1; global_resolution=480; grammarOption=0; level=0; memset(ctrl, 0, NUM_CTRL); glob_num=glob_den=4; global_params[DEFOCT]=3; global_params[DEFVEL]=64; global_params[DEFDUR]=global_resolution; global_params[DEFREL]=0; init_local_flag(); for(i=NUM_VARS; i--;) { global_vars[i].name=NULL; global_vars[i].type=0; global_vars[i].value=0; } if(!(noteVarTemp=(pnote_var)malloc(sizeof(*noteVarTemp)))) sntx_err(MEMORY_ERR, ""); if(!(noteVarTemp->name=(char *)malloc((1+VAR_LENGTH)*sizeof(char)))) sntx_err(MEMORY_ERR, ""); noteVarTemp->type=0; noteVarTemp->value=0; if(!(noteVarTempBis=(pnote_var)malloc(sizeof(*noteVarTempBis)))) sntx_err(MEMORY_ERR, ""); if(!(noteVarTempBis->name=(char *)malloc((1+VAR_LENGTH)*sizeof(char)))) sntx_err(MEMORY_ERR, ""); noteVarTempBis->type=0; noteVarTempBis->value=0; //Initialize the players vector playerCount=0; memset(players, 0, NUM_PLAYERS); for(i=NUM_MACRO; i--;) macros[i].name=macros[i].data=NULL; //Initialize the pseudo-random numbers generator init_rand(); } void init_player(void) { register unsigned int i; if(!(players[playerCount]=(pPlayer)malloc(sizeof(player)))) sntx_err(MEMORY_ERR, ""); players[playerCount]->identifier=NULL; for(i=NUM_VARS; i--;) { players[playerCount]->local_vars[i].name=NULL; players[playerCount]->local_vars[i].type=0; players[playerCount]->local_vars[i].value=0; } for(i=NUM_PRODS; i--;) { players[playerCount]->productions[i]=NULL; } players[playerCount]->num=players[playerCount]->den= players[playerCount]->iterations= players[playerCount]->local_params[DEFOCT]= players[playerCount]->local_params[DEFVEL]= players[playerCount]->local_params[DEFDUR]= players[playerCount]->local_params[DEFREL]= players[playerCount]->local_params[DEFINSTR]= players[playerCount]->local_params[CHN]=0; } gramophone-0.8.13a/midicode.c0000644000175000017500000000763510757737531016264 0ustar giovannigiovanni/* * GRAMophone II, a grammar based algorithmic musical composition tool * -------------------------------------------------------------------- * * midicode.c * * Copyright (c) 2007, Giovanni Ferranti * * GRAMophone II is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ------------------------------------------------------------------- */ #include "global.h" extern char idTemp[]; unsigned int id; void gen_code(unsigned int op, unsigned int op1) { id=hash(idTemp, 0); players[playerCount]->productions[id]-> midicode[players[playerCount]->productions[id]->cc][0]=op; players[playerCount]->productions[id]-> midicode[players[playerCount]->productions[id]->cc++][1]=op1; } void gen_code2(unsigned int op) { id=hash(idTemp, 0); players[playerCount]->productions[id]-> midicode[players[playerCount]->productions[id]->cc++][0]=op; } void code_update(unsigned int cc, unsigned int _goto) { id=hash(idTemp, 0); players[playerCount]->productions[id]-> midicode[_goto][2]=cc; } void gen_code3(unsigned int op, unsigned type, unsigned op1) { id=hash(idTemp, 0); players[playerCount]->productions[id]-> midicode[players[playerCount]->productions[id]->cc][0]=op; players[playerCount]->productions[id]-> midicode[players[playerCount]->productions[id]->cc][1]=type; players[playerCount]->productions[id]-> midicode[players[playerCount]->productions[id]->cc++][2]=op1; } void gen_code4(unsigned int op, unsigned op1, unsigned op2, unsigned type) { id=hash(idTemp, 0); players[playerCount]->productions[id]-> midicode[players[playerCount]->productions[id]->cc][0]=op; players[playerCount]->productions[id]-> midicode[players[playerCount]->productions[id]->cc][1]=op1; players[playerCount]->productions[id]-> midicode[players[playerCount]->productions[id]->cc][2]=op2; players[playerCount]->productions[id]-> midicode[players[playerCount]->productions[id]->cc++][3]=type; } void gen_note_code(unsigned int op, unsigned int note, unsigned int type1, unsigned int op1, unsigned int type2, unsigned int op2, unsigned int type3, unsigned int op3, unsigned int type4, unsigned int op4) { id=hash(idTemp, 0); players[playerCount]->productions[id]-> midicode[players[playerCount]->productions[id]->cc][0]=op; players[playerCount]->productions[id]-> midicode[players[playerCount]->productions[id]->cc][1]=note; players[playerCount]->productions[id]-> midicode[players[playerCount]->productions[id]->cc][2]=type1; players[playerCount]->productions[id]-> midicode[players[playerCount]->productions[id]->cc][3]=op1; players[playerCount]->productions[id]-> midicode[players[playerCount]->productions[id]->cc][4]=type2; players[playerCount]->productions[id]-> midicode[players[playerCount]->productions[id]->cc][5]=op2; players[playerCount]->productions[id]-> midicode[players[playerCount]->productions[id]->cc][6]=type3; players[playerCount]->productions[id]-> midicode[players[playerCount]->productions[id]->cc][7]=op3; players[playerCount]->productions[id]-> midicode[players[playerCount]->productions[id]->cc][8]=type4; players[playerCount]->productions[id]-> midicode[players[playerCount]->productions[id]->cc++][9]=op4; } gramophone-0.8.13a/midifile.c0000644000175000017500000004513410757737531016265 0ustar giovannigiovanni/* * midifile 1.11 * * Read and write a MIDI file. Externally-assigned function pointers are * called upon recognizing things in the file. * * Original release ? * June 1989 - Added writing capability, M. Czeiszperger. * * The file format implemented here is called * Standard MIDI Files, and is part of the Musical * instrument Digital Interface specification. * The spec is avaiable from: * * International MIDI Association * 5316 West 57th Street * Los Angeles, CA 90056 * * An in-depth description of the spec can also be found * in the article "Introducing Standard MIDI Files", published * in Electronic Musician magazine, April, 1989. * */ #include "midifile.h" #define NULLFUNC 0 #define NULL 0 #include #include char *strcpy(), *strcat(); void exit(), free(); /* public stuff */ /* Functions to be called while processing the MIDI file. */ int (*Mf_getc)() = NULLFUNC; int (*Mf_error)() = NULLFUNC; int (*Mf_header)() = NULLFUNC; int (*Mf_trackstart)() = NULLFUNC; int (*Mf_trackend)() = NULLFUNC; int (*Mf_noteon)() = NULLFUNC; int (*Mf_noteoff)() = NULLFUNC; int (*Mf_pressure)() = NULLFUNC; int (*Mf_parameter)() = NULLFUNC; int (*Mf_pitchbend)() = NULLFUNC; int (*Mf_program)() = NULLFUNC; int (*Mf_chanpressure)() = NULLFUNC; int (*Mf_sysex)() = NULLFUNC; int (*Mf_arbitrary)() = NULLFUNC; int (*Mf_metamisc)() = NULLFUNC; int (*Mf_seqnum)() = NULLFUNC; int (*Mf_eot)() = NULLFUNC; int (*Mf_smpte)() = NULLFUNC; int (*Mf_tempo)() = NULLFUNC; int (*Mf_timesig)() = NULLFUNC; int (*Mf_keysig)() = NULLFUNC; int (*Mf_seqspecific)() = NULLFUNC; int (*Mf_text)() = NULLFUNC; /* Functions to implement in order to write a MIDI file */ int (*Mf_putc)() = NULLFUNC; int (*Mf_writetrack)() = NULLFUNC; int (*Mf_writetempotrack)() = NULLFUNC; int Mf_nomerge = 0; /* 1 => continue'ed system exclusives are */ /* not collapsed. */ long Mf_currtime = 0L; /* current time in delta-time units */ /* private stuff */ static long Mf_toberead = 0L; static long Mf_numbyteswritten = 0L; static long readvarinum(); static long read32bit(); static long to32bit(); static int read16bit(); static int to16bit(); static char *msg(); /* * Write multi-length bytes to MIDI format files */ void WriteVarLen(value) unsigned long value; { unsigned long buffer; buffer = value & 0x7f; while((value >>= 7) > 0) { buffer <<= 8; buffer |= 0x80; buffer += (value & 0x7f); } while(1){ eputc((unsigned)(buffer & 0xff)); if(buffer & 0x80) buffer >>= 8; else return; } }/* end of WriteVarLen */ mfread() /* The only non-static function in this file. */ { if ( Mf_getc == NULLFUNC ) mferror("mfread() called without setting Mf_getc"); readheader(); while ( readtrack() ) ; } /* for backward compatibility with the original lib */ midifile() { mfread(); } //static readmt(s) /* read through the "MThd" or "MTrk" header string */ char *s; { int n = 0; char *p = s; int c; while ( n++<4 && (c=(*Mf_getc)()) != EOF ) { if ( c != *p++ ) { char buff[32]; (void) strcpy(buff,"expecting "); (void) strcat(buff,s); mferror(buff); } } return(c); } //static egetc() /* read a single character and abort on EOF */ { int c = (*Mf_getc)(); if ( c == EOF ) mferror("premature EOF"); Mf_toberead--; return(c); } //static readheader() /* read a header chunk */ { int format, ntrks, division; if ( readmt("MThd") == EOF ) return; Mf_toberead = read32bit(); format = read16bit(); ntrks = read16bit(); division = read16bit(); if ( Mf_header ) (*Mf_header)(format,ntrks,division); /* flush any extra stuff, in case the length of header is not 6 */ while ( Mf_toberead > 0 ) (void) egetc(); } //static readtrack() /* read a track chunk */ { /* This array is indexed by the high half of a status byte. It's */ /* value is either the number of bytes needed (1 or 2) for a channel */ /* message, or 0 (meaning it's not a channel message). */ static int chantype[] = { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 through 0x70 */ 2, 2, 2, 2, 1, 1, 2, 0 /* 0x80 through 0xf0 */ }; long lookfor; int c, c1, type; int sysexcontinue = 0; /* 1 if last message was an unfinished sysex */ int running = 0; /* 1 when running status used */ int status = 0; /* status value (e.g. 0x90==note-on) */ int needed; if ( readmt("MTrk") == EOF ) return(0); Mf_toberead = read32bit(); Mf_currtime = 0; if ( Mf_trackstart ) (*Mf_trackstart)(); while ( Mf_toberead > 0 ) { Mf_currtime += readvarinum(); /* delta time */ c = egetc(); if ( sysexcontinue && c != 0xf7 ) mferror("didn't find expected continuation of a sysex"); if ( (c & 0x80) == 0 ) { /* running status? */ if ( status == 0 ) mferror("unexpected running status"); running = 1; } else { status = c; running = 0; } needed = chantype[ (status>>4) & 0xf ]; if ( needed ) { /* ie. is it a channel message? */ if ( running ) c1 = c; else c1 = egetc(); chanmessage( status, c1, (needed>1) ? egetc() : 0 ); continue;; } switch ( c ) { case 0xff: /* meta event */ type = egetc(); lookfor = Mf_toberead - readvarinum(); msginit(); while ( Mf_toberead > lookfor ) msgadd(egetc()); metaevent(type); break; case 0xf0: /* start of system exclusive */ lookfor = Mf_toberead - readvarinum(); msginit(); msgadd(0xf0); while ( Mf_toberead > lookfor ) msgadd(c=egetc()); if ( c==0xf7 || Mf_nomerge==0 ) sysex(); else sysexcontinue = 1; /* merge into next msg */ break; case 0xf7: /* sysex continuation or arbitrary stuff */ lookfor = Mf_toberead - readvarinum(); if ( ! sysexcontinue ) msginit(); while ( Mf_toberead > lookfor ) msgadd(c=egetc()); if ( ! sysexcontinue ) { if ( Mf_arbitrary ) (*Mf_arbitrary)(msgleng(),msg()); } else if ( c == 0xf7 ) { sysex(); sysexcontinue = 0; } break; default: badbyte(c); break; } } if ( Mf_trackend ) (*Mf_trackend)(); return(1); } //static badbyte(c) int c; { char buff[32]; (void) sprintf(buff,"unexpected byte: 0x%02x",c); mferror(buff); } //static metaevent(type) { int leng = msgleng(); char *m = msg(); switch ( type ) { case 0x00: if ( Mf_seqnum ) (*Mf_seqnum)(to16bit(m[0],m[1])); break; case 0x01: /* Text event */ case 0x02: /* Copyright notice */ case 0x03: /* Sequence/Track name */ case 0x04: /* Instrument name */ case 0x05: /* Lyric */ case 0x06: /* Marker */ case 0x07: /* Cue point */ case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: /* These are all text events */ if ( Mf_text ) (*Mf_text)(type,leng,m); break; case 0x2f: /* End of Track */ if ( Mf_eot ) (*Mf_eot)(); break; case 0x51: /* Set tempo */ if ( Mf_tempo ) (*Mf_tempo)(to32bit(0,m[0],m[1],m[2])); break; case 0x54: if ( Mf_smpte ) (*Mf_smpte)(m[0],m[1],m[2],m[3],m[4]); break; case 0x58: if ( Mf_timesig ) (*Mf_timesig)(m[0],m[1],m[2],m[3]); break; case 0x59: if ( Mf_keysig ) (*Mf_keysig)(m[0],m[1]); break; case 0x7f: if ( Mf_seqspecific ) (*Mf_seqspecific)(leng,m); break; default: if ( Mf_metamisc ) (*Mf_metamisc)(type,leng,m); } } //static sysex() { if ( Mf_sysex ) (*Mf_sysex)(msgleng(),msg()); } //static chanmessage(status,c1,c2) int status; int c1, c2; { int chan = status & 0xf; switch ( status & 0xf0 ) { case 0x80: if ( Mf_noteoff ) (*Mf_noteoff)(chan,c1,c2); break; case 0x90: if ( Mf_noteon ) (*Mf_noteon)(chan,c1,c2); break; case 0xa0: if ( Mf_pressure ) (*Mf_pressure)(chan,c1,c2); break; case 0xb0: if ( Mf_parameter ) (*Mf_parameter)(chan,c1,c2); break; case 0xe0: if ( Mf_pitchbend ) (*Mf_pitchbend)(chan,c1,c2); break; case 0xc0: if ( Mf_program ) (*Mf_program)(chan,c1); break; case 0xd0: if ( Mf_chanpressure ) (*Mf_chanpressure)(chan,c1); break; } } /* readvarinum - read a varying-length number, and return the */ /* number of characters it took. */ static long readvarinum() { long value; int c; c = egetc(); value = c; if ( c & 0x80 ) { value &= 0x7f; do { c = egetc(); value = (value << 7) + (c & 0x7f); } while (c & 0x80); } return (value); } static long to32bit(c1,c2,c3,c4) { long value = 0L; value = (c1 & 0xff); value = (value<<8) + (c2 & 0xff); value = (value<<8) + (c3 & 0xff); value = (value<<8) + (c4 & 0xff); return (value); } static to16bit(c1,c2) int c1, c2; { return ((c1 & 0xff ) << 8) + (c2 & 0xff); } static long read32bit() { int c1, c2, c3, c4; c1 = egetc(); c2 = egetc(); c3 = egetc(); c4 = egetc(); return to32bit(c1,c2,c3,c4); } static read16bit() { int c1, c2; c1 = egetc(); c2 = egetc(); return to16bit(c1,c2); } /* static */ mferror(s) char *s; { if ( Mf_error ) (*Mf_error)(s); exit(1); } /* The code below allows collection of a system exclusive message of */ /* arbitrary length. The Msgbuff is expanded as necessary. The only */ /* visible data/routines are msginit(), msgadd(), msg(), msgleng(). */ #define MSGINCREMENT 128 static char *Msgbuff = NULL; /* message buffer */ static int Msgsize = 0; /* Size of currently allocated Msg */ static int Msgindex = 0; /* index of next available location in Msg */ //static msginit() { Msgindex = 0; } static char * msg() { return(Msgbuff); } //static msgleng() { return(Msgindex); } //static msgadd(c) int c; { /* If necessary, allocate larger message buffer. */ if ( Msgindex >= Msgsize ) biggermsg(); Msgbuff[Msgindex++] = c; } //static biggermsg() { /* char *malloc(); */ char *newmess; char *oldmess = Msgbuff; int oldleng = Msgsize; Msgsize += MSGINCREMENT; newmess = (char *) malloc( (unsigned)(sizeof(char)*Msgsize) ); if(newmess == NULL) mferror("malloc error!"); /* copy old message into larger new one */ if ( oldmess != NULL ) { register char *p = newmess; register char *q = oldmess; register char *endq = &oldmess[oldleng]; for ( ; q!=endq ; p++,q++ ) *p = *q; free(oldmess); } Msgbuff = newmess; } /* * mfwrite() - The only fuction you'll need to call to write out * a midi file. * * format 0 - Single multi-channel track * 1 - Multiple simultaneous tracks * 2 - One or more sequentially independent * single track patterns * ntracks The number of tracks in the file. * division This is kind of tricky, it can represent two * things, depending on whether it is positive or negative * (bit 15 set or not). If bit 15 of division is zero, * bits 14 through 0 represent the number of delta-time * "ticks" which make up a quarter note. If bit 15 of * division is a one, delta-times in a file correspond to * subdivisions of a second similiar to SMPTE and MIDI * time code. In this format bits 14 through 8 contain * one of four values - 24, -25, -29, or -30, * corresponding to the four standard SMPTE and MIDI * time code frame per second formats, where -29 * represents 30 drop frame. The second byte * consisting of bits 7 through 0 corresponds the the * resolution within a frame. Refer the Standard MIDI * Files 1.0 spec for more details. * fp This should be the open file pointer to the file you * want to write. It will have be a global in order * to work with Mf_putc. */ void mfwrite(format,ntracks,division,fp) int format,ntracks,division; FILE *fp; { int i; void mf_write_track_chunk(), mf_write_header_chunk(); if ( Mf_putc == NULLFUNC ) mferror("mfmf_write() called without setting Mf_putc"); if ( Mf_writetrack == NULLFUNC ) mferror("mfmf_write() called without setting Mf_mf_writetrack"); /* every MIDI file starts with a header */ mf_write_header_chunk(format,ntracks,division); /* In format 1 files, the first track is a tempo map */ if(format == 1 && ( Mf_writetempotrack )) { (*Mf_writetempotrack)(); } /* The rest of the file is a series of tracks */ for(i = 0; i < ntracks; i++) mf_write_track_chunk(i,fp); } void mf_write_track_chunk(which_track,fp) int which_track; FILE *fp; { unsigned long trkhdr,trklength; long offset, place_marker; void write16bit(),write32bit(); trkhdr = MTrk; trklength = 0; /* Remember where the length was written, because we don't know how long it will be until we've finished writing */ offset = ftell(fp); #ifdef DEBUG printf("offset = %d\n",(int) offset); #endif /* Write the track chunk header */ write32bit(trkhdr); write32bit(trklength); Mf_numbyteswritten = 0L; /* the header's length doesn't count */ if( Mf_writetrack ) { (*Mf_writetrack)(which_track); } /* mf_write End of track meta event */ eputc(0); eputc(meta_event); eputc(end_of_track); eputc(0); /* It's impossible to know how long the track chunk will be beforehand, so the position of the track length data is kept so that it can be written after the chunk has been generated */ place_marker = ftell(fp); /* This method turned out not to be portable because the parameter returned from ftell is not guaranteed to be in bytes on every machine */ /* track.length = place_marker - offset - (long) sizeof(track); */ #ifdef DEBUG printf("length = %d\n",(int) trklength); #endif if(fseek(fp,offset,0) < 0) mferror("error seeking during final stage of write"); trklength = Mf_numbyteswritten; /* Re-mf_write the track chunk header with right length */ write32bit(trkhdr); write32bit(trklength); fseek(fp,place_marker,0); } /* End gen_track_chunk() */ void mf_write_header_chunk(format,ntracks,division) int format,ntracks,division; { unsigned long ident,length; void write16bit(),write32bit(); ident = MThd; /* Head chunk identifier */ length = 6; /* Chunk length */ /* individual bytes of the header must be written separately to preserve byte order across cpu types :-( */ write32bit(ident); write32bit(length); write16bit(format); write16bit(ntracks); write16bit(division); } /* end gen_header_chunk() */ /* * mf_write_midi_event() * * Library routine to mf_write a single MIDI track event in the standard MIDI * file format. The format is: * * * * In this case, event can be any multi-byte midi message, such as * "note on", "note off", etc. * * delta_time - the time in ticks since the last event. * type - the type of meta event. * chan - The midi channel. * data - A pointer to a block of chars containing the META EVENT, * data. * size - The length of the meta-event data. */ int mf_write_midi_event(delta_time, type, chan, data, size) unsigned long delta_time; unsigned int chan,type; unsigned long size; unsigned char *data; { int i; //void WriteVarLen(); unsigned char c; WriteVarLen(delta_time); /* all MIDI events start with the type in the first four bits, and the channel in the lower four bits */ c = type | chan; if(chan > 15) perror("error: MIDI channel greater than 16\n"); eputc(c); /* write out the data bytes */ for(i = 0; i < size; i++) eputc(data[i]); return(size); } /* end mf_write MIDI event */ /* * mf_write_meta_event() * * Library routine to mf_write a single meta event in the standard MIDI * file format. The format of a meta event is: * * * * delta_time - the time in ticks since the last event. * type - the type of meta event. * data - A pointer to a block of chars containing the META EVENT, * data. * size - The length of the meta-event data. */ int mf_write_meta_event(delta_time, type, data, size) unsigned long delta_time; unsigned char *data,type; unsigned long size; { int i; WriteVarLen(delta_time); /* This marks the fact we're writing a meta-event */ eputc(meta_event); /* The type of meta event */ eputc(type); /* The length of the data bytes to follow */ WriteVarLen(size); for(i = 0; i < size; i++) { if(eputc(data[i]) != data[i]) return(-1); } return(size); } /* end mf_write_meta_event */ void mf_write_tempo(tempo) unsigned long tempo; { /* Write tempo */ /* all tempos are written as 120 beats/minute, */ /* expressed in microseconds/quarter note */ eputc(0); eputc(meta_event); eputc(set_tempo); eputc(3); eputc((unsigned)(0xff & (tempo >> 16))); eputc((unsigned)(0xff & (tempo >> 8))); eputc((unsigned)(0xff & tempo)); } unsigned long mf_sec2ticks(secs,division,tempo) int division; unsigned int tempo; float secs; { return (long)(((secs * 1000.0) / 4.0 * division) / tempo); } /* * This routine converts delta times in ticks into seconds. The * else statement is needed because the formula is different for tracks * based on notes and tracks based on SMPTE times. * */ float mf_ticks2sec(ticks,division,tempo) int division; unsigned int tempo; unsigned long ticks; { float smpte_format, smpte_resolution; if(division > 0) return ((float) (((float)(ticks) * (float)(tempo)) / ((float)(division) * 1000000.0))); else { smpte_format = upperbyte(division); smpte_resolution = lowerbyte(division); return (float) ((float) ticks / (smpte_format * smpte_resolution * 1000000.0)); } } /* end of ticks2sec() */ /* * write32bit() * write16bit() * * These routines are used to make sure that the byte order of * the various data types remains constant between machines. This * helps make sure that the code will be portable from one system * to the next. It is slightly dangerous that it assumes that longs * have at least 32 bits and ints have at least 16 bits, but this * has been true at least on PCs, UNIX machines, and Macintosh's. * */ void write32bit(data) unsigned long data; { eputc((unsigned)((data >> 24) & 0xff)); eputc((unsigned)((data >> 16) & 0xff)); eputc((unsigned)((data >> 8 ) & 0xff)); eputc((unsigned)(data & 0xff)); } void write16bit(data) int data; { eputc((unsigned)((data & 0xff00) >> 8)); eputc((unsigned)(data & 0xff)); } /* write a single character and abort on error */ eputc(c) unsigned char c; { int return_val; if((Mf_putc) == NULLFUNC) { mferror("Mf_putc undefined"); return(-1); } return_val = (Mf_putc)(c); if ( return_val == EOF ) mferror("error writing"); Mf_numbyteswritten++; return(return_val); } gramophone-0.8.13a/midifile.h0000644000175000017500000000632510757737531016271 0ustar giovannigiovanni/* definitions for MIDI file parsing code */ extern int (*Mf_getc)(); extern int (*Mf_header)(); extern int (*Mf_trackstart)(); extern int (*Mf_trackend)(); extern int (*Mf_noteon)(); extern int (*Mf_noteoff)(); extern int (*Mf_pressure)(); extern int (*Mf_parameter)(); extern int (*Mf_pitchbend)(); extern int (*Mf_program)(); extern int (*Mf_chanpressure)(); extern int (*Mf_sysex)(); extern int (*Mf_metamisc)(); extern int (*Mf_seqspecific)(); extern int (*Mf_seqnum)(); extern int (*Mf_text)(); extern int (*Mf_eot)(); extern int (*Mf_timesig)(); extern int (*Mf_smpte)(); extern int (*Mf_tempo)(); extern int (*Mf_keysig)(); extern int (*Mf_arbitrary)(); extern int (*Mf_error)(); extern long Mf_currtime; extern int Mf_nomerge; /* definitions for MIDI file writing code */ extern int (*Mf_putc)(); extern int (*Mf_writetrack)(); extern int (*Mf_writetempotrack)(); float mf_ticks2sec(); unsigned long mf_sec2ticks(); void mfwrite(); /* MIDI status commands most significant bit is 1 */ #define note_off 0x80 #define note_on 0x90 #define poly_aftertouch 0xa0 #define control_change 0xb0 #define program_chng 0xc0 #define channel_aftertouch 0xd0 #define pitch_wheel 0xe0 #define system_exclusive 0xf0 #define delay_packet (1111) /* 7 bit controllers */ #define damper_pedal 0x40 #define portamento 0x41 #define sostenuto 0x42 #define soft_pedal 0x43 #define general_4 0x44 #define hold_2 0x45 #define general_5 0x50 #define general_6 0x51 #define general_7 0x52 #define general_8 0x53 #define tremolo_depth 0x5c #define chorus_depth 0x5d #define detune 0x5e #define phaser_depth 0x5f /* parameter values */ #define data_inc 0x60 #define data_dec 0x61 /* parameter selection */ #define non_reg_lsb 0x62 #define non_reg_msb 0x63 #define reg_lsb 0x64 #define reg_msb 0x65 /* Standard MIDI Files meta event definitions */ #define meta_event 0xFF #define sequence_number 0x00 #define text_event 0x01 #define copyright_notice 0x02 #define sequence_name 0x03 #define instrument_name 0x04 #define lyric 0x05 #define marker 0x06 #define cue_point 0x07 #define channel_prefix 0x20 #define end_of_track 0x2f #define set_tempo 0x51 #define smpte_offset 0x54 #define time_signature 0x58 #define key_signature 0x59 #define sequencer_specific 0x74 /* Manufacturer's ID number */ #define Seq_Circuits (0x01) /* Sequential Circuits Inc. */ #define Big_Briar (0x02) /* Big Briar Inc. */ #define Octave (0x03) /* Octave/Plateau */ #define Moog (0x04) /* Moog Music */ #define Passport (0x05) /* Passport Designs */ #define Lexicon (0x06) /* Lexicon */ #define Tempi (0x20) /* Bon Tempi */ #define Siel (0x21) /* S.I.E.L. */ #define Kawai (0x41) #define Roland (0x42) #define Korg (0x42) #define Yamaha (0x43) /* miscellaneous definitions */ #define MThd 0x4d546864 #define MTrk 0x4d54726b #define lowerbyte(x) ((unsigned char)(x & 0xff)) #define upperbyte(x) ((unsigned char)((x & 0xff00)>>8)) gramophone-0.8.13a/man/0000755000175000017500000000000011004322202015046 5ustar giovannigiovannigramophone-0.8.13a/man/man1/0000755000175000017500000000000011004322171015707 5ustar giovannigiovannigramophone-0.8.13a/man/man1/gramophone2.10000644000175000017500000004620111004322004020210 0ustar giovannigiovanni<<<<<<< .mine .TH gramophone2 1 "17 Agosto, 2007" "versione 0.5.1a" "GRAMophone II user manual" ======= .TH gramophone2 1 "30 November , 2007" "version 0.5.13a" "GRAMophone II user manual" >>>>>>> .r30 .SH "NAME" gramophone2 \- GRAMophone is an algorithmic generator of music composition. .SH "SYNOPSYS" .B gramophone2 [\-c|\-d] sourcefile [midifile] .SH "OPTIONS" .TP .I "\-c" is an option allowing you to control the syntax of the source without generating music. .TP .I "\-d" is an option allowing you to activate debug mode, with video output of the composition and player parameters plus the generated notes. .SH "DESCRIPTION" In GRAMophone, the music is generated using two kinds of formal grammar: Chomsky's regular grammar (or Type 3) for a TOP DOWN approach to the composition and a reduced version of Lindenmayer grammar for a BOTTOM UP approach. .SH "BASIC CONCEPT OF GRAMophone" GRAMophone is partly based on an idea of Jon McCormack's, who invented the idea of a virtual player (virtual musician). The player in question is associated with a MIDI track, and interprets instructions telling it what to do. Generally, they say play notes (send MIDI messages). GRAMophone's players together make up an orchestra, which plays a composition. .PP Any number of players can play a composition, but in practice the hardware used might impose an upper limit. .PP In general every player plays an instrument and each has a different set of grammar rules. An individual player is characterised by a set of parameters which are shared by the whole orchestra and/or a personal parameter set. .TP The orchestra's parameters consist of: the kind of grammar used (Chomsky or Lindenmayer); the metronome; the measure; the number of iterations used in the production process. .TP Each individual player's parameters consist of: the kind of grammar used (Chomsky or Lindenmayer); the instrument; the MIDI channel associated with the player; the number of iterations used in the production process; .TP A player's notes have a current state consisting of: octave volume duration release .PP These characteristics can be controlled parametrically by a player declaring its associated variables. GRAMophone, then, allows for the non-deterministic generation of music, using either Chomsky or Lindenmayer grammar. .SH "GUIDE TO GRAMophone" "Give Me A" (The "Hello, World!" for GRAMophone") To introduce you to the basic ideas, here is the simplest algorithmic composition that can be generated with GRAMophone: this composition simply generates the note A and is presented through both the Chomsky and Lindenmayer methods. .nf composition "Give Me A" of "Schroeder" { //this composition generates the A note with the Chomsky grammar grammar chomsky tempo 120 time_signature 4/4 % player Schroeder { instrument 0 % @composition->A[,,,]; } } composition "Give Me A" of "Schroeder" { //this composition generates the A note with the Lindenmayer grammar grammar lindenmayer tempo 120 time_signature 4/4 % player Schroeder { instrument 0 % axiom->A[,,,]; } } .fi THE KEYWORDS composition E of All compositions must begin with the keyword composition followed by a string (in inverted commas) containing the name of the composition. This must be followed by the keyword of then another string containing the copyright of the piece. THE COMPOSITION BLOCK The composition block is placed in brackets. It is subdivided into three sections: one section defines parameters of the composition, one declares and initiates any global variables and an orchestra section where the players who will 'play' the piece are defined. The first two sections are separated by the % symbol. THE player KEYWORD Each player is defined with the keyword player, followed by an identifier. THE player BLOCK The player block is placed in brackets and is divided into three sections: one section defines the parameters of the track associated with the player, one declares any local variables for the player and one is for the formal rules. The first two sections are separated by the % symbol. COMMENTS In GRAMophone, comments are C-like: they must begin with the character pair '/*' and end with the character pair '*/.' There must be no space between the asterisk and the slash. Everything between these pairs of symbols will be ignored by the GRAMophone parser. Whole lines of comments may also be included. Lines of comments begin with the symbol // and end at the end of the line, as in the two initial examples. Section defining the composition's parameters .TP The parameters shared by all the orchestra's players are declared here. The parameters that may be declared are: grammar resolution iterations tempo time_signature .PP This section must end with the % symbol. grammar This parameter is obligatory and defines the kind of grammar to be used in the generation. This can be either chomsky or lindenmayer. resolution This parameter defines the number of time units of 1/4 duration. If omitted, the default value 480 will be used. iterations This parameter defines the number of iterations contained in the generation. Its meaning depends on the kind of grammar chosen, as explained below. If omitted, the default value 1 will be used. tempo This parameter defines the composition's rhythm. If omitted, the default value 120 will be used. time_signature This parameter defines the composition's measure. If omitted, the default value 4/4 will be used. Section declaring the composition's global variables The variables control the parameters of a note's attributes, as explained below. Section defining the player's parameters .TP Each player's personal parameters and variables are declared here. The personal parameters that may be declared are: instrument channel iterations This section must end with the % symbol. instrument .TP This parameter indicates the player's instrument type. GRAMophone's instrument set is the same as that of General MIDI. The acceptable range of values is 0 to 127; there are therefore 128 instruments to choose from. A table showing the instrument codes appears below: 0 Piano 1 Brite Piano 2 HammerPiano 3 Honkey Tonk 4 New Tines 5 Digital Piano 6 Harpsichord 7 Clavi 8 Celesta 9 Glocken 10 Music Box 11 Vibes 12 Marimba 13 Xylophon 14 Tubular Bell 15 Santur 16 Full Organ 17 Percussive Organ 18 BX-3 Organ 19 Church Organ 20 Positive 21 Musette 22 Harmonica 23 Tango 24 Classic Guitar 25 Acoustic Guitar 26 Jazz Guitar 27 Clean Guitar 28 Mute Guitar 29 Overdrive Guitar 30 Distorted Guitar 31 Harmonics 32 Jazz Bass 33 Deep Bass 34 Pick Bass 35 Fretless Bass 36 Slap Bass 1 37 Slap Bass 2 38 Syntethized Bass 1 39 Syntethized Bass 2 40 Violin 41 Viola 42 Cello 43 Contra Bass 44 Tremolo String 45 Pizzicato 46 Harp 47 Timpani 48 Marcato 49 Slow String 50 Analog Pad 51 String Pad 52 Choir 53 Doo Voice 54 Voices 55 Orchestra Hit 56 Trumpet 57 Trombone 58 Tuba 59 Mute Trumpet 60 French Horn 61 Brass Section 62 Synthetized Brass 1 63 Synthetized Brass 2 64 Soprano Sax 65 Alto Sax 66 Tenor Sax 67 Baritone Sax 68 Sweet Oboe 69 English Horn 70 Bassoon Oboe 71 Clarinet 72 Piccolo 73 Flute 74 Recorder 75 Pan Flute 76 Bottle 77 Shakhukuhachi 78 Whistle 79 Ocarina 80 Square Lead 81 Saw Lead 82 Caliope Lead 83 Chiff Lead 84 Charang Lead 85 Air Chorus 86 Rezzo4ths 87 Bass & Lead 88 Fantasia 89 Warm Pad 90 Poly Synth Pad 91 Ghost Pad 92 Bowed Pad 93 Metal Pad 94 Halo Pad 95 Sweep Pad 96 Ice Rain 97 Soundtrack 98 Crystal 99 Atmosphere 100 Brightness 101 Goblin 102 Echo Drop 103 Star Theme 104 Sitar 105 Banjo 106 Shamisen 107 Koto 108 Kalimba 109 Scotland 110 Fiddle 111 Shanai 112 Metal Bell 113 Agogo 114 Steel Drums 115 Wood Blok 116 Taiko Drum 117 Melodic Tom 118 Synth Tom 119 Reverse Cymbal 120 Fret Noise 121 Noise Chiff 122 Seashore 123 Birds 124 Telephone 125 Helicopter 126 Stadium!! 127 Gunshot .PP If omitted, the default instrument value 0 is used. channel This parameter defines which Midi channel will be associated with the player. There are 16 possible channels. Channel 10 is reserved for percussion instruments. If omitted, the default channel value 1 is used. iterations This parameter defines the number of iterations in the generation. Its meaning depends on the kind of grammar chosen, as explained below. If the iterations parameter has been included in the composition declarations, the latter declaration will be ignored. Section declaring the player's local variables The variables control the parameters of a note's attributes, as explained below. Notes in GRAMophone HOW NOTES ARE WRITTEN DOWN IN GRAMophone Notes are the first category of terminal symbols GRAMophone. .TP GRAMophone uses the English notation for notes: A B C D E F G .PP The names of notes must be written in capital letters. The flat and sharp symbols are represented by 'b' and '#' respectively; no space should appear between these symbols and the name of the note: A#, Gb, etc. .PP NOTE ATTRIBUTES Notes can have four attributes in GRAMophone: octave, velocity, duration and release. The octave attribute varies between \-2 and 8, while the velocity and release attributes vary from 0 to 127. If the note is written without attributes, then the following default values are used: 3 for octave, 64 for velocity and release. The current default value for duration is a crotchet. In the example, "Give me A" is written simply as A[,,,]. This means that an A is generated at the third octave, with a duration of 1/4 and a velocity and release of 64. DEFINING THE ATTRIBUTES OF A NOTE The attributes of a note are defined by writing them inside the square brackets which follow the name of the note, without spaces. A note can have four attributes at most and each attribute type may have only one value. .TP The attributes must be defined in the following order: octave velocity duration release .PP If all three attributes are not defined, the default value is used for the missing ones. .TP Here are some examples of notes with attributes: C[2, 50+60/2, 240*4,] \- plays a C at the second octave, with a velocity of 80, duration of 960 (minim with a resolution of 480) and a release of 64 (default value); Db[4,,,] \- plays a D flat at the fourth octave, using the default values for velocity, duration and release; F#[,,,] \- use the default values for all the attributes; .TP Incorrect examples are: Db[3, 127, 960, 64, x] \- too many attributes (x is a variable). .PP PAUSE Pauses are another category of terminal symbol in GRAMophone. They are indicated by the letter R and only take a duration type attribute. If unspecified, the default resolution value is used. Attributes are defined in the same way as for notes. .TP Here are some examples of pauses: R[480/2] \- pause with a duration of 240; R[] \- use the default value for the attribute of type duration. .PP CHORDS Chords are the final category of terminal symbol used in GRAMophone. A chord is a series of notes played simultaneously. In GRAMophone, notes played in a chord are enclosed between two '^' symbols. .TP Here are some examples of chords: ^C[,,,]E[,,,]G[,,,]^ \- plays a C major chord, using each note's default values. ^A[2,80,240,]C[2,,240,]E[2,,240,]^ \- plays an A minor chord with duration 1/8, with all notes at the second octave and velocity 64 (default value), with the first note of the chord played with a velocity of 80 and the remaining two at a velocity of 64 (default value). .PP THE ROLE OF R IN COMPLEX CHORDS The notes of a chord do not always have the same duration. For example it is possible that, while the note C[2,,1920,] of duration 4/4 is playing, the musician has to play four crotchets in the following order: C[,,,], E[,,,], G[,,,], Bb[,,,]. There has to be a way of telling GRAMophone that the notes C[2,,1920,] and C[,,,] must start at the same time, that E[,,,] must begin after a pause of 1/4, G[,,,] after 2/4 and Bb[,,,] after 3/4. In GRAMophone this is written as follows: ^C[2,,1920,]C[,,,]R[]E[,,,]R[960]G[,,,]R[1440]Bb[,,,]^ In other words, every note in the chord can be preceded by a pause definition representing the time to wait before playing the note. It does not matter which order you write the notes down in a chord. The chord in the example above can also be written: ^R[]E[,,,]C[2,,1920,]R[1440]Bb[,,,]C[,,,]R[960]G[,,,]^ IDENTIFIERS Some of GRAMophone's language entities, variables, macros and non-terminal symbols in Chomsky grammar for example, must have names by which they can be identified. These names are called identifiers and are chosen by the composer. GRAMophone's identifiers follow the system of identifiers used in the programming language Pascal. In fact an identifier is made up of a letter followed by a sequence of letters or digits. GRAMophone's identifiers must also be written in lower case. Chomsky Grammar NON-TERMINAL SYMBOLS In Chomsky grammar non-terminal symbols are used to give a structure or 'style' to the musical composition. They are written with an '@' immediately followed by an identifier. The Chomsky grammar used by GRAMophone is context free so the head of the production can only be a non-terminal. THE NON-TERMINAL SYMBOL @composition This non-terminal symbol, which corresponds to the final composition of a single player, is obligatory. PRODUCTION OPERATOR This is defined by the character sequence '->' and separates the head of the production from the body. BODY OF THE PRODUCTION This may contain sequences of terminal (notes, pauses and chords) and non-terminal symbols. Each production must end with a semi-colon. | (OR) OPERATOR A production may be non-deterministic: in other words it may present two or more choices during generation. The body of a non-deterministic production is made up of the various choices separated by the | operator. For example @non_det->A[,,,]B[,,,]@Seq1|^A[,,,]B[,,,]C[,,,]^@Seq2R[]C[,,,]; is a non-deterministic production. MEANING OF ITERATION IN CHOMSKY GRAMMAR In Chomsky grammar a production may include cycles, i.e. production bodies containing non-terminal symbols that refer to the production actually being produced. For example: @Sequenza1->B[,,,]A[,,,]C[,,,]@Sequenza1; To avoid an infinite loop during generation, the non-terminal symbol @Sequenza1 is processed an equal number of times to the iterations parameter. Lindenmayer Grammar Lindenmayer grammar only deals with terminal symbols and GRAMophone's version can be context-free or work in a polyphonic context. Therefore, single notes or chords can appear at the head of the production. All productions are separated by a semi-colon. AXIOM This is the initial production from which generation begins. It is obligatory. PRODUCTION OPERATOR This is defined by the character sequence '->' and separates the head of the production from the body. | (OR) OPERATOR A production may be non-deterministic: in other words it may present two or more choices during generation. The body of a non-deterministic production is made up of the various choices separated by the | operator. For example A[,,,]->A[,,,]B[,,,]|C[,,,]D[,,,]; is a non-deterministic production. MEANING OF ITERATIONS IN LINDENMAYER GRAMMAR At each step all the grammar's productions are simultaneously applied to the note string. In this case the iterations parameter represents the number of steps to be carried out. Use of variables DECLARATION AND INITIALISATION OF VARIABLES GRAMophone is able to control the attributes of a note parametrically through the use of variables. These variables are declared in the player's declaration section and may be of the following types: octave, velocity, duration and msb. A variable is declared by writing its type followed by one or more identifiers separated by a comma. The declaration must end with a semi-colon. A player's identifier must be declared only once. .TP The following are correct declarations: velocity x, y; octave oct, z; duration w; .TP The following are incorrect declarations: velocity x, x; octave z; duration z; .PP Following the declaration section and before the grammar it is possible to initialise variables by means of the = operator. .TP The following is an example of declaration and initialisation: velocity x; x=0; .PP USING VARIABLES WITH NOTES Variables are used in note attribute expressions. GRAMophone controls the types within expressions, so it is not possible to add an octave variable to a velocity variable, for example. .TP The following is an example of a note variable: velocity x; duration z, w; A[4,x,z+w,]. .PP EXAMPLE .nf composition "Crescendo" of "Schroeder" { //this composition generates 64 A notes with a growing velocity grammar chomsky tempo 120 time_signature 4/4 iterations 64 % player Schroeder { instrument 40 % velocity x=0; @composition->A[,x=x+1,,]@composition; } } .fi CONDITIONS In both Chomsky and Lindenmayer grammars it is possible to define conditions for the variables in the production body. If the condition is true, the production is executed; otherwise it is not. A condition is defined immediately after the name of the production by means of the '?' symbol, followed by one or more Boolean expressions. .TP The Boolean operators are: ! not && and || or .TP The relational operators are: == uguale != diverso < minore > maggiore <= minore o uguale >= maggiore o uguale .PP The following is an example of a conditional production. @battuta?x!=0->A[,x=x-10,,]@battuta; which means: while x is not equal to zero, generate the @battuta production; otherwise do not. Discography, GRAMophone's library GRAMophone is able to include external libraries, called discographies. To include a discography in a source file, use the keyword discography followed by its file name. A discography can be included at any point in the source file, as long as its contents match the position of the source where it has been included. Macros Macros can be defined using the keyword define, followed by a lower-case identifier and a string placed in inverted commas. Macros must be defined at the beginning of the source composition, before the composition keyword. For example, in order to simply write a instead of A[,,,], the following macro must be defined: define a "A[,,,]" Functions in GRAMophone THE repeat() FUNCTION The repeat() function takes an msb type value plus a Chomsky or Lindenmayer sequence. It enables the included sequence to be repeated a number of times that is equal to the msb type value. THE rand() FUNCTION The rand() function takes an expression and returns a random value which is less than the value of the expression. Melodic operators in GRAMophone transpose() The transpose() operator takes an msb type value plus a Chomsky or Lindenmayer sequence. It generates a sequence in which all the notes in the relevant sequence are transposed by a number of semitones equal to the msb type value. inversion() The inversion() operator takes a Chomsky or Lindenmayer sequence. It generates a sequence in which the intervals between the first and the other notes in the sequence taken are calculated in reverse. retrograde() The retrograde() operator takes a Chomsky or Lindenmayer sequence. It generates a sequence which is the contrary of the sequence inserted. .SH "AUTHOR" Giovanni Ferranti gramophone-0.8.13a/man/it/0000755000175000017500000000000011004322205015465 5ustar giovannigiovannigramophone-0.8.13a/man/it/man1/0000755000175000017500000000000011004322217016324 5ustar giovannigiovannigramophone-0.8.13a/man/it/man1/gramophone2.10000644000175000017500000005316511004322004020633 0ustar giovannigiovanni.TH gramophone2 1 "30 Novembre, 2007" "versione 0.5.13a" "Manuale utente di GRAMophone II" .SH "NOME" gramophone2 \- GRAMophone e' un generatore algoritmico per la composizione musicale. .SH "USO" .B gramophone2 [\-c|\-d] sourcefile [midifile] .SH "OPZIONI" .TP .I "\-c" e' un'opzione che consente di effettuare semplicemente il controllo della sintassi del sorgente senza generare la musica. .TP .I "\-d" e' un'opzione che consente di attivare una modalita' di debug, con stampa a video dei valori dei parametri della composition, dei parametri dei players e delle note generate. .SH "DESCRIZIONE" In GRAMophone la generazione della musica viene realizzata tramite l'uso di due tipi di grammatiche formali: la grammatica regolare di Chomsky (o di tipo 3) per un approccio TOP DOWN alla composizione e una versione ridotta della grammatica di Lindenmayer per un approccio BOTTOM UP. .SH "CONCETTI BASE DI GRAMophone" GRAMophone si basa in parte su un'idea di Jon McCormack, da cui riprende il concetto di virtual player (musicista virtuale). Il player e' associato ad una traccia MIDI ed e' responsabile per l'interpretazione delle istruzioni che gli vengono date, che nel caso generale significa suonare note (mandare messaggi MIDI). L'insieme dei player in GRAMophone forma l'orchestra, che esegue una compositione. .PP Un qualunque numero di player puo' essere impiegato in una composition, anche se le caratteristiche dell'hardware potrebbero fissare una limitazione sul numero. .PP Generalmente ogni player suona un proprio strumento e ciascuno ha un insieme differente di regole. Un singolo player e' caratterizzato da un insieme di parametri comuni a tutta l'orchestra e/o un insieme di parametri personali. .TP I parametri che caratterizzano l'orchestra sono: il tipo di grammatica utilizzata per la generazione (Chomsky o Lindenmayer); il metronomo; la misura; il numero di iterazioni per il processo delle produzioni. .TP Le caratteristiche personali di ciascun player sono: il tipo di grammatica utilizzata per la generazione (Chomsky o Lindenmayer); lo strumento suonato; il canale MIDI a cui e' associato; il numero di iterazioni per il processo delle produzioni. .TP Le note suonate dai player mantengono uno stato corrente che consiste di: ottava volume durata rilascio .PP Queste caratteristiche possono essere controllate parametricamente tramite la dichiarazione da parte di ciascun player di variabili ad esse associate. GRAMophone, infine, offre la possibilita' di generare musica in maniera non deterministica, sia con la grammatica di Chomsky sia con quella di Lindenmayer. .SH "GUIDA A GRAMophone" Di seguito viene riportata la piu' semplice composizione algoritmica che si puo' generare con GRAMophone, per introdurne i concetti fondamentali. Questa composizione genera semplicemente la nota LA e viene presentata sia con il metodo di Chomsky sia con quello di Lindenmayer. .nf composition "Give Me A" of "Schroeder" { //this composition generates the A note with the Chomsky grammar grammar chomsky tempo 120 time_signature 4/4 % player Schroeder { instrument 0 % @composition->A[,,,]; } } composition "Give Me A" of "Schroeder" { //this composition generates the A note with the Lindenmayer grammar grammar lindenmayer tempo 120 time_signature 4/4 % player Schroeder { instrument 0 % axiom->A[,,,]; } } .fi LE PAROLE CHIAVE composition E of Ogni composizione algoritmica deve iniziare con la parola chiave composition, a cui deve seguire una stringa (racchiusa tra doppi apici) con il nome della composizione. Di seguito e' richiesta la parola chiave of, a cui deve seguire un'altra stringa con il copyright del brano. IL BLOCCO DELLA COMPOSIZIONE Il blocco della composizione e' delimitato dalle parentesi graffe. e' suddiviso in tre sezioni: una sezione per la definizione dei parametri della composizione, una per la dichiarazione e la inizializzazione delle eventuali variabili globali e una sezione orchestra, dove si definiscono i vari player che "suoneranno" il pezzo. Le prime due sezioni sono separate dal simbolo %. LA PAROLA CHIAVE player Ciascun player si definisce tramite la parola chiave player, seguita da un identificatore. IL BLOCCO DEL player Il blocco del player e' delimitato dalle parentesi graffe ed e' diviso in tre sezioni: una sezione per la definizione dei parametri della traccia associata al player, una parte di dichiarazione e inizializzazione per le eventuali variabili locali del player e la sezione per le regole formali. Le prime due sezioni sono separate dal simbolo %. COMMENTI In GRAMophone, i commenti sono C-like: devono iniziare con la coppia di caratteri '/*' e devono terminare con la coppia di caratteri '*/'. Fra l'asterisco e la barra non devono essere inseriti spazi. Tutto cio' che si trova tra queste coppie di simboli verra' ignorato dal parser di GRAMophone. e' possibile definire anche intere linee di commento. Le righe di commento iniziano con il simbolo // e terminano alla fine della riga, come nel caso dei due esempi iniziali. Sezione di definizione parametri della composition .TP Qui si dichiarano i parametri comuni a tutti i player dell'orchestra. I parametri che possono essere dichiarati sono: grammar resolution iterations tempo time_signature .PP Questa sezione deve terminare con il simbolo %. grammar Questo parametro e' obbligatorio e definisce il tipo di grammatica che verra' usato per la generazione. Il tipo puo' essere chomsky o lindenmayer. resolution Questo parametro indica il numero di unita' di tempo per la durata di 1/4. Se omesso, verra' usato il valore di default 480. iterations Questo parametro indica il numero di iterazioni per la generazione. Ha un significato differente a seconda del tipo di grammatica scelto, come verra' spiegato in seguito. Se omesso, viene utilizzato il valore di default 1. tempo Questo parametro indica il metronomo della composizione. Se omesso, viene utilizzato il valore di default 120. time_signature Questo parametro indica la misura della composizione. Se omesso, viene utilizzato il valore di default 4/4. Sezione di dichiarazione variabili globali della composition Le variabili servono per controllare parametricamente gli attributi di una nota e verrano spiegate in seguito. Sezione di definizione parametri del player .TP Qui si dichiarano i parametri personali e le variabili di ciascun player. I parametri personali che possono essere dichiarati sono: instrument channel iterations .PP Questa sezione deve terminare con il simbolo %. instrument .TP Questo parametro indica il tipo di strumento da far suonare al player. Gli strumenti di GRAMophone coincidono con il set di strumenti del General MIDI. Il range di valori accettati va da 0 a 127; ci sono quindi 128 strumenti da cui scegliere. Di seguito viene riportata una tabella con il codice e lo strumento a cui esso fa riferimento: 0 Piano 1 Brite Piano 2 HammerPiano 3 Honkey Tonk 4 New Tines 5 Digital Piano 6 Harpsichord 7 Clavi 8 Celesta 9 Glocken 10 Music Box 11 Vibes 12 Marimba 13 Xylophon 14 Tubular Bell 15 Santur 16 Full Organ 17 Percussive Organ 18 BX-3 Organ 19 Church Organ 20 Positive 21 Musette 22 Harmonica 23 Tango 24 Classic Guitar 25 Acoustic Guitar 26 Jazz Guitar 27 Clean Guitar 28 Mute Guitar 29 Overdrive Guitar 30 Distorted Guitar 31 Harmonics 32 Jazz Bass 33 Deep Bass 34 Pick Bass 35 Fretless Bass 36 Slap Bass 1 37 Slap Bass 2 38 Syntethized Bass 1 39 Syntethized Bass 2 40 Violin 41 Viola 42 Cello 43 Contra Bass 44 Tremolo String 45 Pizzicato 46 Harp 47 Timpani 48 Marcato 49 Slow String 50 Analog Pad 51 String Pad 52 Choir 53 Doo Voice 54 Voices 55 Orchestra Hit 56 Trumpet 57 Trombone 58 Tuba 59 Mute Trumpet 60 French Horn 61 Brass Section 62 Synthetized Brass 1 63 Synthetized Brass 2 64 Soprano Sax 65 Alto Sax 66 Tenor Sax 67 Baritone Sax 68 Sweet Oboe 69 English Horn 70 Bassoon Oboe 71 Clarinet 72 Piccolo 73 Flute 74 Recorder 75 Pan Flute 76 Bottle 77 Shakhukuhachi 78 Whistle 79 Ocarina 80 Square Lead 81 Saw Lead 82 Caliope Lead 83 Chiff Lead 84 Charang Lead 85 Air Chorus 86 Rezzo4ths 87 Bass & Lead 88 Fantasia 89 Warm Pad 90 Poly Synth Pad 91 Ghost Pad 92 Bowed Pad 93 Metal Pad 94 Halo Pad 95 Sweep Pad 96 Ice Rain 97 Soundtrack 98 Crystal 99 Atmosphere 100 Brightness 101 Goblin 102 Echo Drop 103 Star Theme 104 Sitar 105 Banjo 106 Shamisen 107 Koto 108 Kalimba 109 Scotland 110 Fiddle 111 Shanai 112 Metal Bell 113 Agogo 114 Steel Drums 115 Wood Blok 116 Taiko Drum 117 Melodic Tom 118 Synth Tom 119 Reverse Cymbal 120 Fret Noise 121 Noise Chiff 122 Seashore 123 Birds 124 Telephone 125 Helicopter 126 Stadium!! 127 Gunshot .PP Se il parametro instrument viene omesso, viene utilizzato il valore di default 0. channel Questo parametro indica quale canale Midi associare al player. I canali possibili sono 16. Il canale 10 e' speciale ed e' riservato alle percussioni. Se omesso, viene assegnato il valore di default 1. iterations Questo parametro indica il numero di iterazioni per la generazione. Ha un significato differente a seconda del tipo di grammatica scelto, come verra' spiegato in seguito. Se il parametro iterations e' presente anche nella parte dichiarativa della composition, quest'ultimo verra' ignorato. Sezione di dichiarazione variabili locali del player Le variabili servono per controllare parametricamente gli attributi di una nota e verrano spiegate in seguito. COME SI SCRIVONO LE NOTE IN GRAMophone Le note in GRAMophone sono la prima categoria di simboli terminali in GRAMophone. .TP GRAMophone usa la notazione inglese per il nome delle note: la nota LA e' A; la nota SI e' B; la nota DO e' C; la nota RE e' D; la nota MI e' E; la nota FA e' F; la nota SOL e' G; .PP I nomi delle note devono essere scritti obbligatoriamente in maiuscolo. I simboli bemolle e diesis sono rappresentati rispettivamente dal carattere 'b' minuscolo e '#'; essi vanno scritti di seguito senza spazi al nome della nota: A#, Gb, eccetera. ATTRIBUTI DELLE NOTE Le note sono caratterizzate da quattro attributi: l'ottava, l'intensita', la durata e il rilascio. In GRAMophone questi quattro attributi sono chiamati rispettivamente octave, velocity, duration e release. L'attributo octave varia da \-2 a 8, mentre gli attributi velocity e release variano da 0 a 127. Se la nota viene scritta senza specificare alcun attributo, vengono utilizzati i valori di default: 3 per l'ottava, 64 per l'intensita' e il rilascio, il valore di default corrente della resolution (semiminima) per la durata. Nell'esempio "Give me A" nel corpo della produzione e' scritto semplicemente A[,,,]. Questo vuol dire che viene generata una nota LA suonata alla terza ottava, della durata di 1/4 e con un'intensita' ed un rilascio pari a 64. DEFINIRE GLI ATTRIBUTI DI UNA NOTA Per definire gli attributi di una nota, questi vanno scritti all'interno di parentesi quadre che seguono senza spazi il nome della nota. Ciascuna nota puo' avere al massimo quattro attributi e puo' essere definito solo un attributo per ciascun tipo. .TP L'ordine con cui vanno definiti gli attributi di diverso tipo e' il seguente: ottava intensita' durata rilascio .PP Se non vengono definiti tutti e tre i tipi di attributo, per quelli mancati vengono utilizzati i valori di default. .TP Esempi di note con attributi sono i seguenti: C[2, 50+60/2, 240*4,] \- suona un Do alla seconda ottava, con un'intensita' di 80, la durata di 960 (minima con resolution impostata a 480) ed un rilascio di 64 (valore di default); Db[4,,,] \- suona un RE bemolle alla quarta ottava, usando i valori di default per la velocity, la duration e la release; F#[,,,] \- usa i valori di default per tutti gli attributi; .TP Esempi errati sono i seguenti: Db[3, 127, 960, 64, x] \- troppi attributi (x e' una variabile). .PP PAUSE Le pause sono un'altra categoria dei simboli terminali di GRAMophone. Si indicano con la lettera R e accettano solo il tipo di attributo duration. Se non specificato, viene utilizzato il valore di default della resolution. La definizione dell'attributo avviene in maniera analoga alle note. .TP Esempi di pause sono i seguenti: R[480/2] \- una pausa che dura 240 (il tempo di una croma con resolution a 480); R[] \- usa il valore di default per l'attributo di tipo duration. .PP ACCORDI Gli accordi sono l'ultima categoria di simboli terminali usati da GRAMophone. Un accordo e' una serie di note suonate simultaneamente. In GRAMophone le note suonate in un accordo sono racchiuse tra due simboli '^'. .TP Esempi di accordi sono i seguenti: ^C[,,,]E[,,,]G[,,,]^ \- suona un accordo di DO maggiore, utilizzando i valori di default per ciascuna nota. ^A[2,80,240,]C[2,,240,]E[2,,240,]^ \- suona un accordo di LA minore della durata di 1/8, con tutte le note suonate alla seconda ottava con un rilascio di 64 (valore di default), con la prima nota dell'accordo suonata ad un'intensita' di 80 e le restanti due ad un'intensita' di 64 (valore di default). .PP RUOLO DI R NEGLI ACCORDI COMPLESSI Non sempre le note in un accordo hanno la stessa durata. Ad esempio puo' capitare che in una battuta, mentre suona una nota C[2,,1920,] della durata di 4/4, il musicista debba contemporaneamente suonare quattro note della durata di una semiminima ciascuna nel seguente ordine: C[,,,], E[,,,], G[,,,], Bb[,,,]. All'interno dell'accordo quindi bisogna trovare un modo per dire a GRAMophone che le note C[2,,1920,] e C[,,,] devono cominciare a suonare nello stesso istante, che E[,,,] deve iniziare a suonare dopo una pausa di 1/4, G[,,,] dopo 2/4 e Bb[,,,] dopo 3/4. In GRAMophone questo si scrive nella seguente maniera: ^C[2,,1920,]C[,,,]R[]E[,,,]R[960]G[,,,]R[1440]Bb[,,,]^ Cioe' davanti a ciascuna nota dell'accordo si puo' definire una pausa che rappresenta il tempo che bisogna aspettare prima che la nota inizi a suonare. L'ordine con cui si scrivono le note nell'accordo non ha importanza. L'accordo precedente si puo' scrivere anche come: ^R[]E[,,,]C[2,,1920,]R[1440]Bb[,,,]C[,,,]R[960]G[,,,]^ IDENTIFICATORI Alcune entita' del linguaggio di GRAMophone, come ad esempio le variabili, le macros ed i simboli non terminali della grammatica di Chomsky, devono avere dei nomi per mezzo dei quali possano essere identificate. Questi nomi vengono chiamati identificatori e vengono scelti dal compositore. Gli identificatori usati dal linguaggio di GRAMophone riprendono gli identificatori del linguaggio Pascal. Infatti un identificatore e' formato da una lettera seguita da una sequenza di lettere o cifre. Gli identificatori di GRAMophone, inoltre, devono essere obbligatoriamente scritti in minuscolo. Grammatica di Chomsky SIMBOLI NON TERMINALI Nella grammatica di Chomsky i simboli non terminali servono per dare una struttura e uno 'stile' alla composizione musicale. I simboli non terminali si scrivono con un carattere '@' seguito senza spazi da un identificatore. La grammatica di Chomsky utilizzata da GRAMophone e' libera dal contesto, quindi la testa delle produzioni puo' essere solo un non terminale. IL SIMBOLO NON TERMINALE @composition e' il simbolo non terminale che corrisponde a quella che sara' la composizione finale del singolo player ed e' obbligatorio. OPERATORE DI PRODUZIONE e' definito dalla sequenza di caratteri '->' e separa la testa della produzione dal corpo della produzione. CORPO DELLA PRODUZIONE Puo' contenere sequenze di simboli terminali (note, pause e accordi) e di simboli non terminali. Ciascuna produzione deve terminare con un punto e virgola. OPERATORE | (OR) Una produzione puo' essere non deterministica, cioe' presentare due o piu' possibilita' tra cui scegliere durante la generazione. Il corpo di una produzione non deterministica e' formato dalle varie possiblita' separate dall'operatore |. Ad esempio @non_det->A[,,,]B[,,,]@Seq1|^A[,,,]B[,,,]C[,,,]^@Seq2R[]C[,,,]; e' una produzione non deterministica. SIGNIFICATO DELLE ITERAZIONI NELLA GRAMMATICA DI CHOMSKY Nella grammatica di Chomsky possono capitare produzioni che contengono cicli, cioe' produzioni nel cui corpo sono presenti simboli non terminali che fanno riferimento alla produzione che si sta processando, ad esempio: @Sequenza1->B[,,,]A[,,,]C[,,,]@Sequenza1; Per evitare un loop infinito durante la generazione, il simbolo non terminale @Sequenza1 viene processato un numero di volte pari al parametro iterations. Grammatica di Lindenmayer La grammatica di Lindenmayer tratta solo simboli terminali e quella adottata da GRAMophone puo' essere libera dal contesto o operare in un contesto polifonico. Nella testa delle produzioni possono esserci quindi singole note o accordi. Ogni produzione e' separata da un punto e virgola. AXIOM e' la produzione iniziale da cui parte la generazione. e' obbligatoria. OPERATORE DI PRODUZIONE e' definito dalla sequenza di caratteri '->' e separa la testa della produzione dal corpo della produzione. OPERATORE | (OR) Una produzione puo' essere non deterministica, cioe' presentare due o piu' possibilita' tra cui scegliere durante la generazione. Il corpo di una produzione non deterministica e' formato dalle varie possibilita' separate dall'operatore |. Ad esempio A[,,,]->A[,,,]B[,,,]|C[,,,]D[,,,]; e' una produzione non deterministica. SIGNIFICATO DELLE ITERAZIONI NELLA GRAMMATICA DI LINDENMAYER A ciascun passo vengono applicate alla stringa di note corrente tutte le produzioni della grammatica contemporaneamente. Il parametro iterations in questo caso rappresenta il numero di passi da effettuare. Uso delle variabili DICHIARAZIONE E INIZIALIZZAZIONE DELLE VARIABILI GRAMophone e' in grado di controllare gli attributi di una nota parametricamente mediante l'uso di variabili. Queste variabili si dichiarano nella parte dichiarativa del player e possono essere di tipo octave, velocity, duration e msb. Una variabile si dichiara scrivendo il tipo seguito da uno o piu' identificatori separati da una virgola e la dichiarazione dev'essere terminata da un punto e virgola. Per ogni player un identificatore puo' essere dichiarato solo una volta. .TP Sono dichiarazioni corrette le seguenti: velocity x, y; octave oct, z; duration w; .TP Sono dichiarazioni scorrette le seguenti: velocity x, x; octave z; duration z; .PP Dopo la parte dichiarativa e prima della grammatica e' possibile inizializzare le variabili dichiarate mediante l'operatore =. .TP Un Esempio di dichiarazione e inizializzazione e' il seguente: velocity x; x=0; .PP USARE LE VARIABILI CON LE NOTE Le variabili si usano nelle espressioni degli attributi della nota. GRAMophone esegue il controllo dei tipi nelle espressioni, quindi ad esempio non e' possibile sommare una variabile di tipo octave con una di tipo velocita'. .TP Un esempio di nota variabile e' la seguente: velocity x; duration z, w; A[4,x,z+w,]. .PP ESEMPIO .nf composition "Crescendo" of "Schroeder" { //this composition generates 64 A notes with a growing velocity grammar chomsky tempo 120 time_signature 4/4 iterations 64 % player Schroeder { instrument 40 % velocity x=0; @composition->[A,x=x+1,,]@composition; } } .fi CONDIZIONI Nelle produzioni sia della grammatica di Chomsky sia della grammatica di Lindenmayer e' possibile definire delle condizioni sulle variabili eventualmente presenti nel corpo delle produzioni. Se la condizione e' verificata, la produzione viene processata altrimenti no. Una condizione si definisce subito dopo il nome della produzione tramite il simbolo '?' seguito da una o piu' espressioni booleane. .TP Gli operatori booleani sono: ! not && and || or .TP Gli operatori relazionali sono: == uguale != diverso < minore > maggiore <= minore o uguale >= maggiore o uguale .PP Un esempio di produzione con condizione e' la seguente: @battuta?x!=0->A[,x=x-10,,]@battuta; il suo significato e' il seguente: finche' x e' diverso da zero, genera la produzione @battuta, altrimenti no. Discography, la libreria di GRAMophone GRAMophone e' in grado di includere librerie esterne, che vengono chiamate discografie. Per includere in un file sorgente una discografia si usa la parola chiave discography, seguita dal nome del file che la identifica. Una discography puo' essere inclusa in qualsiasi punto del file sorgente, purche' il suo contenuto sia in sintonia con la posizione del sorgente dove e' stata inserita. Macros e' possibile definire macros utilizzando la parola chiave define, seguita da un identificatore scritto obbligatoriamente in minuscolo e da una stringa chiusa tra doppi apici. Le macros vanno definite obbligatoriamente all'inizio della composizione sorgente, prima cioe' della parola chiave composition. Ad esempio, se vogliamo scrivere semplicemente a al posto di A[,,,], bisogna definire la seguente macro: define a "A[,,,]" LA FUNZIONE repeat() La funzione repeat() prende come argomento un valore di tipo msb ed una sequenza di Chomsky o Lindenmayer. Permette di ripetere la sequenza inserita per un numero di volte pari al valore di tipo msb inserito. LA FUNZIONE rand() La funzione rand() prende come argomento un'espressione e ritorna un valore casuale minore del risultato dell'espressione. Operatori melodici di GRAMophone transpose() L'operatore transpose() prende come argomento un valore di tipo msb ed una sequenza di Chomsky o Lindenmayer. Genera una sequenza in cui tutte le note della sequenza presa come argomento vengono trasposte di un numero di semitoni pari al valore di tipo msb inserito. inversion() L'operatore inversion() prende come argomento una sequenza di Chomsky o Lindenmayer. Genera una sequenza in cui gli intervalli tra la prima e le restanti note della sequenza presa come argomento vengono calcolati in direzione opposta. retrograde() L'operatore retrograde() prende come argomento una sequenza di Chomsky o Lindenmayer. Genera una sequenza contraria a quella inserita come argomento. .SH "AUTORE" Giovanni Ferranti