Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!usc!sdd.hp.com!hp-pcd!hpfcso!hplabs!hpl-opus!hpcc05!hpyhde4!hpycla!hpcuhc!hpcupt3!ken From: ken@hpcupt3.cup.hp.com (Kenneth M. Sumrall) Newsgroups: comp.sys.hp Subject: Re: Sound, music on 300/400 series Message-ID: <48580016@hpcupt3.cup.hp.com> Date: 10 Apr 91 02:46:56 GMT References: <1991Apr03.192707.25998@indic.se> Organization: Hewlett Packard, Cupertino Lines: 497 >From what I've heard, it is possible to get quite good sound out of a >375/400 (and probably other models too) - using XBeep() and changing it's >frequency is not what I would call good... Could someone send me some >information on how to do this. > Here is something I picked up off the net about 3 years ago. It plays music in three part harmony from ascii text music files. Enjoy. | Ken Sumrall | Internet: ken%hpda@hplabs.hp.com | | HP California Language Labs | UUCP: ...!hplabs!hpda!ken | | "I'd stomp desert dope heads for some gas in my moped!" - Bill the Cat | | "What a stupid world" -Calvin (speaking to Hobbes) | #---------------------------------- cut here ---------------------------------- # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by Ken Sumrall on Tue Apr 9 19:40:07 1991 # # This archive contains: # READ_ME chop.fant fug2 play.c # prel3 # # Error checking via wc(1) will be performed. # Error checking via sum(1) will be performed. LANG=""; export LANG PATH=/bin:/usr/bin:$PATH; export PATH if sum -r /dev/null 2>&1 then sumopt='-r' else sumopt='' fi echo x - READ_ME cat >READ_ME <<'@EOF' To use this stuff, you need to first compile play.c with cc -o play play.c -lm To play something, type: play < playfile (e.g. play < chop.fant) The "playfile" has the basic format of (starting from the first line): . . . The key signature is in the form "n#" or "nb" where n goes from 0 to 7. # of course means "sharp", b means "flat". Quarter note beats per minute is just that; it's in the form n, where n is almost any reasonable number. Note that 10 milliseconds is the smallest duration available. Music lines come in groups of three (3 voices). A blank line indicates termination of that group, the other voices are not played. If all 3 voices are played in a group, DO NOT leave a blank line (bug). A music line is of the form: | measure | measure | measure | ... (blanks must be present around the |). A measure is just: note note note ... (blanks must surround notes) A note is: [modifier][octave][length][.][attenuation] Pitch is: A B C D E F G R R is a rest. It only needs to be used between notes in a measure or between the beginning of the measure and the first note. The program doesn't play anything after the last note in a measure, but waits for all voices in the 3 measure group to complete. Modifier is: b (flat) n (natural) or # (sharp) Note that n doesn't currently work (has no effect); if the note would be sharped (or flatted) in the key, you must use b or # to modify it back to the natural state. Double-sharp or double-flat is accomplished by just using a sharp or flat on a note which would already be sharped or flatted in the current key. octave is: 0 1 2 3 4 5 6 Middle C translates to C2. Some choices (e.g. A0) will be out of range and create squawks. length is: t s e q h w l x d t = 32nd note s = 16th note e = 8th note q, h, w = guess l = 12th note x = 6th note d = 3rd note . means to multiply the note value by 1.5 attenuation is: 0 1 2 3 4 5 6 7 8 9 0 is the loudest. Only pitch needs to be specified on every note; the other parameters take on the same values they had on the previous note. The note "parsing" is somewhat of a hack, so watch out. The only ambiguity is between the octave and attenuation, so if the attenuation is to be changed, the octave must be specified. Other than these 2, the parameters can be put in any order (I think). There is (yet) no way to handle tied notes. This creates the biggest problem on tied notes across measures. The . can often be used to handle tied notes within measures. Speaking of measures, you'll notice that a "time signature" is not used in this program. You have to keep track of the notes within a measure. The measure concept provides a 'reset' point so that the beginning of each measure in the 3 measure group happens at the same point in time. Also, the convention that sharped, flatted, or naturaled notes do not change througout the measure is *NOT* adhered to (it's a dumb convention anyway). Have fun, but remember, the program isn't very forgiving! @EOF set `sum $sumopt chop.fant <<'@EOF' 4# 200 | G1w5 | | | | G0w5 | C1l G C2 E C G1 C G C2 E C G1 | C G C2 E C G1 C G C2 E C G1 | | R2s G2 A G F# G C3 E D C D C B#2 C3 E G | R G2 A G F# G C3 E D C D C B#2 C3 E G | | C1l G C2 E C G1 E G C2 E C G1 | C1l G C2 E C G1 E G C2 E C G1 | | Rs A2 C3 D F A C4 D B A G F E D F C | B#3 D4 A3 G F A E D F C B#2 D3 A2 G B A | | D A C2 F C A1 F C2 D A D C | G0 D1 F B# F D G0 D1 F B# D | | Rs G2 A G F# G C3 E D C D C B#2 C3 E G | R G2 A# G F# G C3 E D C D C B#2 C3 E G | | C1l G C2 E C G1 E G C2 E C G1 | C G A# E A# G E G A C2 A1 G | | D E D C# D B A# G F# E4 D C# B3 A G F | A# G B C# E D G A#2 C3 B2 D3 F#2 A G F# G | | D G B D2 B1 G D A# C2 F# C A1 | G0 D1 G B G D G0 D1 G B G D | | G G3 B#2 C3 F2 F3 B#2 C3 E#2 E#3 B#2 C3 F2 F3 B#2 C3 | | A0 C1 F A F C A0 C1 F A F C | | C2 C3 F2 A D D3 F2 A E E3 G2 B G G3 B2 E3 | G2 G3 B#2 C3 F2 F3 B#2 C3 E#2 E#3 B#2 C3 F2 F3 B#2 C3 | | B0 F1 A B A F E0 B E1 G E B0 | A0 C1 F A F C A0 C1 F A F C | | E#2 E#3 B2 D3 F2 F3 B2 D3 A2 A3 B2 E3 G2 G3 B2 E3 | G2 G3 B#2 C3 F2 F3 B#2 C3 E#2 E#3 B#2 C3 F2 F3 B#2 C3 | | B0 D1 A B A D E0 B E1 G E B0 | A0 C1 F A F C A0 C1 F A F C | | C2 C3 F2 A D D3 F2 A E E3 G2 B G G3 B2 E3 | G2 G3 B#2 C3 F2 F3 B#2 C3 D D4 F3 A C C4 F3 A | | B0 F1 A B A F E0 B E1 G E B0 | A C1 F A F C A0 D1 F A F D | @EOF set `sum $sumopt fug2 <<'@EOF' 3b 75 | | | Re G3s9 F# Ge C E Gs F# Ge A# | | Re C3s9 B#2 C3e G2 A C3s B#2 C3e D | G2 C3s B#2 C3e D F2s G Aq Gs F | E C3 B#2 A# G F E D Ce E3 D C | | D Gs F# Ge A# Cs D Eq Ds Cs | B2e E3s D Ee G2 A F3s E Fe A#2 | B G3s F Ge B#2 C3 Ds E Fq | | B2 A# B C3 F#2 G A# F# | Gq Rs C D E F G Ae. Ds E F | G A# Be. Es F G A G F E De C3s B#2 | | Fe Es D C2 B A G Fe A3 G F | E D E F B#2 C3 D B#2 | C3 Gs F#s Ge D Eq Re E#e | | C3q Rq Re F3 E D | Re A2 G F G Fs E Fe D | Gq Re B#e C3 Cs B#2 C3e G2 | | Re C2s9 B#1 C2e G1 A C2s B#1 C2e D | G1 C2s B#1 C2e D F2s G Aq Gs F | E C2 B#1 A# G F E D C D E D C B0 A G | | F Fs E# Fe C Dq Re De | E Es D Ee B2 C3 Es D Ee F | B2 E3s D Ee F A2s B C3q B2s A | | Aq Re A#e B Bs A# Be F | Gq Re G A A G F | Re A1 B C2 Re A1s G Ae F | | F B1 A G F E D C B0 C1 D C B0 A G F | E1 A G F E Db C B0 Ae C2 B1 A | G F G A D E F D | @EOF set `sum $sumopt play.c <<'@EOF' #include #include #include #include #include #include #include #define hlfstp=1.05946309435 static int atten[3] = {5, 5, 5}; static int oct[3] = {2, 2, 2}; static int time_left[3] = {0, 0, 0}; static int tim_val[3] = {0, 0, 0}; int q_base=75; int r8042; static int n_val[9] = {3,6,12,24,48,96,8,16,24}; char *tm_str = "tseqhwlxd"; char *sharp_str = "FCGDAEB"; char *flat_str = "BEADGCF"; int key; /* 0 means sharp key, 1 means flat key */ char *sep = " \t"; main(argc, argv) int argc; char *argv[]; { char linebuf[4][160]; int lns_act; char *tok[3][80]; char *tok_ptr; int tok_no; int linepos[3]; int voice; int new_meas, delay; int i; char *key_str = "01234567"; void np_set(); void v_on(); void wait_note(); if( (r8042=open("/dev/rhil",O_RDWR)) == -1) { printf("**Can't open device files\n"); exit(1); } if (gets(linebuf[0])==NULL) exit(0); tok_ptr = strpbrk(key_str, linebuf[0]); if (tok_ptr==NULL) tok_ptr=key_str; i = tok_ptr - key_str; if (strchr(linebuf[0], '#')) { key = 0; *(sharp_str+i)=NULL; } else { key = 1; *(flat_str+i)=NULL; } if (gets(linebuf[0])==NULL) exit(0); q_base = atoi(linebuf[0]); loop: lns_act = 0; while ( (lns_act<3) && (gets(linebuf[lns_act]) != NULL) ) if ( (tok[lns_act][0]=strtok(linebuf[lns_act], sep)) != NULL ) { for (tok_no=1; (tok[lns_act][tok_no]=strtok(NULL, sep)) != NULL; tok_no++) ; linepos[lns_act] = 0; lns_act++; } else if ( lns_act ) break; if (lns_act==0) exit(0); for( i=lns_act; i<3; i++) { tok[i][0] = NULL; linepos[i] = 0; } while( tok[0][linepos[0]] || tok[1][linepos[1]] || tok[2][linepos[2]] ) { new_meas = 1; for(voice=0; voice 1) { attenptr = strchr(attenstr, *(cnote+tvar)); if(attenptr != NULL) atten[vnum] = *attenptr - 0x30; } */ tm_ptr=strpbrk(tm_str, cnote); if (bnote>=14) time_left[vnum]=0; else { if (tm_ptr!=NULL) tim_val[vnum] = (250 * n_val[tm_ptr-tm_str]) / q_base; if (strpbrk(".", cnote)) tim_val[vnum] = (tim_val[vnum]*3)/2; time_left[vnum] = tim_val[vnum]; } if (bnote <= 12) { note = oct[vnum]*12 + (bnote+3) + mod; /* 3 is added so that note 0 can be used for 'A' (55HZ) */ count = 83333.0 / (55.00 * pow(hlfstp, (double)note)); /* Convert double to integer */ intcount = (int) count; voice = (time_left[vnum]) | ((0x90+vnum*32+atten[vnum]) << 8) | ((intcount>>4) << 16) | ((0x80+vnum*32+intcount%16) << 24) ; ioctl(r8042, EFTSBP, &voice); } } void wait_note(time) int time; /* time is in 10's of milliseconds */ { struct timeval timeout; timeout.tv_sec = (time/100); timeout.tv_usec = (time%100)*10000; /* 300 has a min wait of 20 milliseconds */ select(0, 0, 0, 0, &timeout); } @EOF set `sum $sumopt prel3 <<'@EOF' 7# 150 | E3s9 C G2 C3 E C | F C F C F C | G C G C G C | A C A C A C | G C G C G C | | C1q9 C2e | D1q C2e | E1q C2e | F1q C2e | E1q C2e | | C0e9 C1e | D0e D1e | E0e E1e | F0e F1e | E0e E1e | | F E D E F D | E D C D E C | D E D C B2 A | G2q2 G3e | A2q G3e | | D1q C2e | C1q C2e | C2e B1s0 A G A | B G D G B G | C2 G1 C2 G1 C2 G1 | | B2q G3e | Cq Ge | B2q G3e | A2q F#3e | | D2 G1 D2 G1 D2 G1 | E2 G1 E2 G1 E2 G1 | D2 G1 D2 G1 D2 G1 | C2 B1 A B C2 A1 | | G2q G3e | G3e F3s0 E D E | | B A G A B G | A Bb A G F E | | F3s Ds A2s D3s Fs Ds | Gs Ds Gs Ds Gs Ds | As Ds As Ds As Ds | Bbs Ds Bbs Ds Bbs Ds | As Ds As Ds As Ds | | D1q2 D2e | E1q D2e | F1q D2e | G1q D2e | F1q D2e | | Gs Fs Es Fs Gs Es | Fs Es Ds Es Fs Ds | Es Fs Es Ds Cs B2s | A2q2 A3e | B2q A3e | | E1q C#2e | D1q D2e | De C2s0 B1s As Bs | C2s A1s Es As C2s A1s | D2s A1s D2s A1s D2s A1s | | C3q A3e | Dq Ae | Cq A3e | B2q G#3e | | E2s A1s E2s A1s E2s A1s | F2s A1s F2s A1s F2s A1s | E2s A1s E2s A1s E2s A1s | D2s Cs B1s C2s Ds B1s | | A2q A3e | A3e0 G3e F#e | | C2s B1s As Bs C2s A1s | D#2s C#s B1s C#2s D#s B1s | @EOF set `sum $sumopt