/* make music for tiny_music player */ #define VERSION "1.0 (2024 Lovebyte)" #include #include #include #include #include #include #include #include #include static int octave_adjust=0; static int notes_used[12*8]; static int allocated_notes[12*8]; static int notes_allocated=0; static int total_len=0; unsigned short frequencies[]={ //C C# D D# E F F# G G# A A# B 0x7A3,0x735,0x6CD,0x66C,0x60F,0x5B8,0x566,0x518,0x4CF,0x48A,0x449,0x40B, //1 0x3D1,0x39A,0x366,0x336,0x307,0x2DC,0x2B3,0x28C,0x267,0x245,0x224,0x205, //2 0x1E8,0x1CD,0x1B3,0x19B,0x183,0x16E,0x159,0x146,0x133,0x122,0x112,0x102, //3 0x0F4,0x0E6,0x0D9,0x0CD,0x0C1,0x0B7,0x0AC,0x0A3,0x099,0x091,0x089,0x081, //4 0x07A,0x073,0x06C,0x066,0x060,0x05B,0x056,0x051,0x04C,0x048,0x044,0x040, //5 0x03D,0x039,0x036,0x033,0x030,0x02D,0x02B,0x028,0x026,0x024,0x022,0x020, //6 //0x01E,0x01C,0x01B,0x019,0x018,0x016,0x015,0x014,0x013,0x012,0x011,0x010, //0x00F,0x00E,0x00D,0x00C,0x00C,0x00B,0x00A,0x00A,0x009,0x009,0x008,0x008, }; static char last_note[4]="A#2"; int note_to_ed(char note, int flat, int sharp, int octave) { int offset; switch(note) { case 'C': offset=0; break; case 'D': offset=2; break; case 'E': offset=4; break; case 'F': offset=5; break; case 'G': offset=7; break; case 'A': offset=9; break; case 'B': offset=11; break; case 'R': offset=12; flat=0; sharp=0; octave=3; break; default: fprintf(stderr,"Unknown note %c\n",note); return -1; } if (flat==1) offset--; if (sharp==1) offset++; if (sharp==2) offset+=2; last_note[0]=note; if (sharp==1) last_note[1]='#'; else last_note[1]=' '; last_note[2]=octave+'0'; offset=((((octave+octave_adjust)-1)&0x7)*12)+offset; // offset=((((octave+octave_adjust)-3)&0x3)<<4)|offset; return offset; } static int debug=0; static int line=0; static int header_version=0; static int current_frame=0; struct note_type { unsigned char which; unsigned char note; int sharp,flat; int octave; int len; int enabled; int freq; int length; int left; int ed_freq; int offset; }; static int allocate_note(int which) { int i; for(i=0;isharp=0; n->flat=0; n->ed_freq=-1; n->note=ch; sp++; if (string[sp]==' ') ; else if (string[sp]=='#') n->sharp=1; else if (string[sp]=='-') n->flat=1; else if (string[sp]=='=') n->flat=2; else { fprintf(stderr,"Unknown note modifier %c, line %d:%d\n", string[sp],line,sp); fprintf(stderr,"String: %s\n",string); } // printf("Sharp=%d Flat=%d\n",n->sharp,n->flat); sp++; n->octave=string[sp]-'0'; sp++; sp++; n->len=string[sp]-'0'; sp++; if (n->note!='-') { freq=note_to_ed(n->note,n->flat,n->sharp, n->octave); if (freq<0) fprintf(stderr,"Bad note line %d\n",line); n->enabled=1; n->length=0; n->ed_freq=freq; } if (header_version==2) sp+=6; return sp; } static int get_string(char *string, char *key, char *output, int strip_linefeed) { char *found; found=strstr(string,key); found=found+strlen(key); /* get rid of leading whitespace */ while(1) { if ((*found==' ') || (*found=='\t')) found++; else break; } strcpy(output,found); /* remove trailing linefeed */ if (strip_linefeed) output[strlen(output)-1]=0; return 0; } static void print_help(int just_version, char *exec_name) { printf("\ntext_to_ed version %s by Vince Weaver \n\n",VERSION); if (just_version) exit(0); printf("This created Electric Duet files\n\n"); printf("Usage:\n"); printf("\t%s [-h] [-v] [-d] [-o X] [-i X] textfile outbase\n\n", exec_name); printf("\t-h: this help message\n"); printf("\t-v: version info\n"); printf("\t-d: print debug messages\n"); printf("\t-o: Offset octave by X\n"); printf("\t-i: set second instrument to X\n"); exit(0); } static int write_note(int *a_last,int *b_last,int *c_last,int total_len) { // this version // NNNNEEEC // NNNNNEEC unsigned char temp_value; unsigned char length=0; if (*a_last>=0) { /* note is shifted left by 3, channel 0 */ temp_value=(*a_last<<4)|0; /* if no note b, use the passed in length */ if ((*b_last<0) && (*c_last<0)) { if (total_len>7) { fprintf(stderr,"Warning: length too big %d\n",total_len); } length=(total_len<<1); temp_value|=length; } printf("\t.byte $%02X ; frame=%d A=%d L=%d\n", temp_value, current_frame, *a_last,length>>1);//(*b_last<0)||(*c_last<0)); // (total_len)++; *a_last=-1; } if (*b_last>=0) { /* note is shifted left by 3, channel 1 */ temp_value=(*b_last<<4)|1; if (total_len>7) { fprintf(stderr,"Warning: length too big %d\n",total_len); } length=(total_len<<1); temp_value|=length; if (*c_last>=0) { // temp_value|=2; fprintf(stderr,"Error, shouldn't have C\n"); } printf("\t.byte $%02X ; frame=%d B=%d L=%d\n", temp_value, current_frame, *b_last,length>>1); // (total_len)++; *b_last=-1; } if (*c_last>=0) { fprintf(stderr,"Unsupported C!\n"); // printf("\t.byte $%02X ; C=%d L=%d\n", // (unsigned char)(*c_last<<3)|4|2, // *c_last,1); // (total_len)++; // *c_last=-1; } return 0; } int main(int argc, char **argv) { char string[BUFSIZ]; char *result; char *in_filename; char temp[BUFSIZ]; FILE *in_file=NULL; //int attributes=0; int loop=0; int sp,external_frequency,irq; struct note_type a,b,c; int copt; int total_length=0; char song_name[BUFSIZ]; char author_name[BUFSIZ]; char comments[BUFSIZ]; char *comments_ptr=comments; // unsigned char sharp_char[]=" #-="; /* Parse command line arguments */ while ((copt = getopt(argc, argv, "dhvo:i:"))!=-1) { switch (copt) { case 'd': /* Debug messages */ printf("Debug enabled\n"); debug=1; break; case 'h': /* help */ print_help(0,argv[0]); break; case 'v': /* version */ print_help(1,argv[0]); break; case 'o': /* octave offset */ octave_adjust=atoi(optarg); break; default: print_help(0,argv[0]); break; } } if (argv[optind]!=NULL) { /* Open the input file */ if (argv[optind][0]=='-') { in_file=stdin; } else { in_filename=strdup(argv[optind]); in_file=fopen(in_filename,"r"); if (in_file==NULL) { fprintf(stderr,"Couldn't open %s\n",in_filename); return -1; } } } /* Get the info for the header */ while(1) { result=fgets(string,BUFSIZ,in_file); if (result==NULL) break; line++; if (strstr(string,"ENDHEADER")) break; if (strstr(string,"HEADER:")) { get_string(string,"HEADER:",temp,1); header_version=atoi(temp); printf("Found header version %d\n",header_version); } if (strstr(string,"TITLE:")) { get_string(string,"TITLE:",song_name,1); } if (strstr(string,"AUTHOR:")) { get_string(string,"AUTHOR:",author_name,1); } if (strstr(string,"COMMENTS:")) { get_string(string,"COMMENTS:",comments_ptr,0); comments_ptr=&comments[strlen(comments)]; } if (strstr(string,"FREQ:")) { get_string(string,"FREQ:",temp,1); external_frequency=atoi(temp); } if (strstr(string,"IRQ:")) { get_string(string,"IRQ:",temp,1); irq=atoi(temp); } if (strstr(string,"LOOP:")) { get_string(string,"LOOP:",temp,1); loop=atoi(temp); } } a.which='A'; b.which='B'; c.which='C'; // algorithm // get A,B,C // int first=1; // int a_last=0,b_last=0,same_count=0; // int a_len=0,b_len=0,a_freq=0,b_freq=0; int current_length=0; int first=1; int a_last=-1,b_last=-1,c_last=-1; printf("; Made with version %s\n",VERSION); printf("peasant_song:\n"); printf("; register init\n"); //printf("\t.byte $00,$00,$00,$00,$00,$00 ; $00: A/B/C fine/coarse\n"); //printf("\t.byte $00 ; $06\n"); //printf("\t.byte $38 ; $07 mixer (ABC on)\n"); //printf("\t.byte $0E,$0C,$0C ; $08 volume A/B/C\n"); //printf("\t.byte $00,$00,$00,$00 ; $09\n"); printf("\n"); while(1) { result=fgets(string,BUFSIZ,in_file); if (result==NULL) break; line++; a.ed_freq=-1; b.ed_freq=-1; c.ed_freq=-1; a.length=0; b.length=0; c.length=0; /* skip comments */ if (string[0]=='\'') continue; if (string[0]=='-') continue; if (string[0]=='*') continue; if (string[0]=='t') { /* track */ if (!first) { printf("; last: a=%d b=%d len=%d\n",a_last,b_last,current_length); write_note(&a_last,&b_last,&c_last,current_length); printf(".byte $ff\n"); } printf("%s\n",string); total_length=0; current_frame=0; current_length=0; continue; } sp=0; /* Skip line number */ while((string[sp]!=' ' && string[sp]!='\t')) sp++; sp=get_note(string,sp,&a,line); if (sp!=-1) sp=get_note(string,sp,&b,line); if (sp!=-1) sp=get_note(string,sp,&c,line); if (a.ed_freq>=0) { a.offset=allocate_note(a.ed_freq); notes_used[a.ed_freq]++; printf("; A: '%s' %d\n",last_note,a.ed_freq); } if (b.ed_freq>=0) { b.offset=allocate_note(b.ed_freq); notes_used[b.ed_freq]++; printf("; B: '%s' %d\n",last_note,b.ed_freq); } if (c.ed_freq>=0) { c.offset=allocate_note(c.ed_freq); notes_used[c.ed_freq]++; printf("; C: %d\n",c.ed_freq); } if ((a.ed_freq>=0)||(b.ed_freq>=0)||(c.ed_freq>=0)) { // now NNNNNNEC if (!first) { write_note(&a_last,&b_last,&c_last, current_length); } // printf("; frame %d: a=%d b=%d len=%d\n", // total_length,a_last,b_last,current_length); total_length+=current_length; current_length=0; //if (!first) { // printf("\t.byte $%02X ; L = %d\n", // current_length|0xc0,current_length); // printf("\n"); // current_length=0; // total_len++; //} first=0; } if (a.ed_freq>=0) { a_last=a.offset; } if (b.ed_freq>=0) { b_last=b.offset; } if (c.ed_freq>=0) { c_last=c.offset; } current_length++; current_frame++; } printf("; last: a=%d b=%d len=%d\n",a_last,b_last,current_length); write_note(&a_last,&b_last,&c_last,current_length); // printf("\t.byte $FF ; end\n"); /* assume 32 notes or fewer */ printf("\t.byte $FF ; end\n"); total_len++; int o,n; for(o=0;o<6;o++) { printf("; Octave %d : ",o); for(n=0;n<12;n++) { printf("%d ",notes_used[(o*12)+n]); } printf("\n"); } printf("; %d notes allocated\n",notes_allocated); printf(";.byte "); for(n=0;n>8)); if (n!=(notes_allocated-1)) printf(","); total_len++; } printf("\n"); printf("; total len=%d\n",total_len); (void) irq; (void) loop; (void) external_frequency; return 0; }