jpederse@encad.Wichita.NCR.COM (John Pedersen) (02/13/88)
Some time back, someone posted a short C program for the s300 that played some tune like "Baby Elephant Walk" or something like that. I kept another article that did some basic chords on the system, but didn't save the posting that had the tune. Anyone keep it and care to e-mail or repost? Need a change from instrument control programming, and this might provide some needed relief. -- John Pedersen
matt@shorty.CS.WISC.EDU (Mad Matt Schaefer) (02/17/88)
In article <254@encad.Wichita.NCR.COM> jpederse@encad.Wichita.NCR.COM (John Pedersen) writes: >Some time back, someone posted a short C program for the s300 that played >some tune like "Baby Elephant Walk" or something like that. I kept another >article that did some basic chords on the system, but didn't save the posting >that had the tune. >Anyone keep it and care to e-mail or repost? If somebody has this I would like a copy as well. I have been wondering how to access the sound chip on the 300. Mad Matt Schaefer ...!{harvard,ihnp4,rutgers,ucbvax}!uwvax!matt UW-Madison Computer Sciences Laboratory matt@cs.wisc.edu
fritz@hpfclp.HP.COM (Gary Fritz) (02/18/88)
I have emailed a copy of the documentation to John. If anyone else would like it, let me know. Gary Fritz
jack@csccat.UUCP (Jack Hudler) (02/19/88)
In article <5247@spool.cs.wisc.edu> matt@cs.wisc.edu (Mad Matt Schaefer) writes: >In article <254@encad.Wichita.NCR.COM> jpederse@encad.Wichita.NCR.COM (John Pedersen) writes: >>Some time back, someone posted a short C program for the s300 that played >>some tune like "Baby Elephant Walk" or something like that. I kept another >>article that did some basic chords on the system, but didn't save the posting >>that had the tune. Will I saved it.. Use it for a mail received cutness. Here it is in the original shar. A version in LISP and C. Jack@csccat #!/bin/sh # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Contents: README Makefile dbsetup.sl music.c beeper.c mytune.h echo x - README sed 's/^@//' > "README" <<'@//E*O*F README//' For those who my not know, the beeper on gators/bobcats have four independent voices. Three of these have a programmable tone, and the fouth is a noise generator. Someone wrote some low level code to talk to the beeper. I wrote some PSL code that allows you to write music in an easy to read format (See example in the file dbsetup.sl). More recently, I translated the functions into C and wrote a function that would take the lisp lists and generate C data structures that could be interpreted by the C code. Anyone who is running Horizon (nmode? prism? whatever...) should be able to write music immediately. Everyone else can build the example C program and hear what the machine can do. Perhaps someone without nmode will be inspired to write a nicer front end. @//E*O*F README// chmod u=rw,g=r,o=r README echo x - Makefile sed 's/^@//' > "Makefile" <<'@//E*O*F Makefile//' it: music music.o: music.c mytune.h cc -c music.c beeper.o: beeper.c cc -c beeper.c music: music.o beeper.o cc -o music music.o beeper.o shar: shar -c README Makefile dbsetup.sl music.c beeper.c mytune.h > music.shar @//E*O*F Makefile// chmod u=rw,g=rw,o=r Makefile echo x - dbsetup.sl sed 's/^@//' > "dbsetup.sl" <<'@//E*O*F dbsetup.sl//' %Get Compiled C code (lisp:load-ofile "/usr/local/src/nmode/beeper/beeper.o" :libs "") (lisp:ff beep "_beep" :parms (nil nil nil nil)) (lisp:ff noise "_noise" :parms (nil nil nil nil)) (lisp:ff beep-or-noise-duration-left "_beep_or_noise_left" :parms (nil)) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Set up tempo variable and note values %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % (when (null (find-package "music")) % (make-package "music")) % % (setf music::old-package *package*) % (in-package 'music) % % (import 'pnth (find-package "music")) (setf tempo 100) (setf whole 1000) (setf half (/ whole 2)) (setf quarter (/ half 2)) (setf eighth (/ quarter 2)) (setf sixteenth (/ eighth 2)) (setf thirtysecond (/ sixteenth 2)) (setf dot-quarter (+ quarter eighth)) (setf dot-half (+ half quarter)) (setf dot-eighth (+ eighth sixteenth)) (setf triplet (/ quarter 3)) (setf rest -1) (setf r -1) (setf C 0) (setf C-sharp 1) (setf cs 1) (setf D 2) (setf ds 3) (setf E-flat 3) (setf Ef 3) (setf E 4) (setf F 5) (setf F-sharp 6) (setf Fs 6) (setf G 7) (setf G-sharp 8) (setf Gs 8) (setf A-flat 8) (setf Af 8) (setf A 9) (setf B-flat 10) (setf Bf 10) (setf B 11) (setf tw whole) (setf th half) (setf tq quarter) (setf te eighth) (setf ts sixteenth) (setf ts1 (+ ts 1)) (setf tdh dot-half) (setf tdq dot-quarter) (setf tde dot-eighth) (setf tt triplet) (setf scale % (vector % (vector 1 510 770 896 959 992) % (vector 50 540 784 902 962 994) % (vector 100 570 798 909 966 996) % (vector 150 600 811 914 970 998) % (vector 200 630 823 922 973 999) % (vector 250 650 837 928 975 1000) % (vector 300 670 849 934 978 1001) % (vector 350 690 857 939 981 1002) % (vector 390 710 866 945 984 1003) % (vector 420 723 874 950 986 1004) % (vector 450 740 882 953 988 1005) % (vector 480 760 891 956 990 1006) % ) (vector (vector 0 386 705 864 943 984)% c (vector 0 422 722 873 948 0) % c# (vector 0 456 739 881 952 0) % d (vector 0 487 755 889 956 0) % d# (vector 12 518 770 897 960 0) % e (vector 69 546 784 904 963 0) % f (vector 123 573 798 911 967 0) % f# (vector 173 598 810 916 970 0) % g (vector 220 622 822 922 973 0) % g# (vector 266 645 834 928 976 0) % a (vector 308 665 844 933 978 0) % a# (vector 348 685 854 938 981 0) % b ) ) (de get-note (pitch octave) (let ((real-pitch (+ pitch pitch-offset)) (real-octave (+ octave octave-offset)) ) (when (>= real-pitch 12) (setf real-pitch (- real-pitch 12)) (setf real-octave (+ real-octave 1)) ) (when (< real-pitch 0) (setf real-pitch (+ real-pitch 12)) (setf real-octave (- real-octave 1)) ) (vector-fetch (vector-fetch scale real-pitch) real-octave) )) % (de get-note (pitch octave) % (vector-fetch (vector-fetch scale pitch) octave) % ) (de note (pitch octave voice duration) (if (eq pitch -1) % it is a rest; (beep voice 0 0 (/ (* 10 duration) tempo)) % otherwise; (beep voice (get-note pitch octave) vol (/ (* 10 duration) tempo)) )) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Set-up Musical Environment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% (setq vol 11) % Volume Setting (setf octave-offset 0) (setf pitch-offset 0) %Last note finished, now go on (defun go-on () (repeat (beep-or-noise-duration-left 1) (= (beep-or-noise-duration-left 1) 0)) ) (defun go-on-voice (voice-num) (repeat (beep-or-noise-duration-left voice-num) (= (beep-or-noise-duration-left voice-num) 0)) ) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Music structure: % % For each voice, there are parallel lists for the notes, the octaves, % and the times; % % A stanza is a list of either 3,6,9,or 12 lists; (depending on how many % voices you use; % % sample stanza: % % (setf stanza % (list (list a b b-flat f-sharp) % (list 1 1 2 1 ) % (list whole whole half quarter) % % (list a b b-flat g ) % (list 2 2 3 2 ) % (list whole whole half quarter) % ) % ) % % Music task structure: % % [ element # % time-to-go 0 % voice-num 1 % ( notes ) 2 % ( octave ) 3 % ( time ) 4 % ] % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% (defun play-stanza (stanza) (let ((time-to-go-idx 0) (voice-num-idx 1) (notes-idx 2) (octaves-idx 3) (times-idx 4) (queue nil) (voice-num nil) (wait-time nil) (temp nil) ) % translate music symbols to numbers; % (for (in list stanza) (do % (for (on i list) (do % (when (null (numberp (car i))) % (setf (car i) (cdr (assoc (car i) music-symbols))) % ) % )) % )) % build a task for each voice; (setf voice-num 1) (while stanza (push (vector 0 voice-num (first stanza) (second stanza) (third stanza) ) queue) (setf voice-num (+ voice-num 1)) (setf stanza (pnth stanza 4)) ) % while there are voices to be played; (while queue % give more data to voices that are ready; (for (in task queue) (with notes octaves times time-to-go) (do % a voice ready for another note; (when (eq 0 (vector-fetch task time-to-go-idx)) (setf notes (vector-fetch task notes-idx)) (setf octaves (vector-fetch task octaves-idx)) (setf times (vector-fetch task times-idx)) (setf time-to-go (first times)) % play a note on this voice; (note (first notes) (first octaves) (vector-fetch task voice-num-idx) time-to-go) (vector-store task time-to-go-idx time-to-go) (vector-store task octaves-idx (rest octaves)) (vector-store task times-idx (rest times)) (vector-store task notes-idx (rest notes)) ) )) % find the task with the shortest time and we'll decrement % the other tasks by its time and wait on it; (setf wait-time 10000) (for (in task queue) (do (when (< (setf temp (vector-fetch task time-to-go-idx)) wait-time) (setf wait-time temp) (setf voice-num (vector-fetch task voice-num-idx)) ) )) % update the time of all tasks; (for (in task queue) (do (vector-store task time-to-go-idx (- (vector-fetch task time-to-go-idx) wait-time) ) )) % wait on the voice that will be done first; (go-on-voice voice-num) % remove voices with no more notes; (setf temp queue) (for (in task temp) (do (when (null (vector-fetch task notes-idx)) (setf queue (delete task queue)) ) )) ) )) % end of function play-stanza; % (setf stanza1 (list % % first trumpet % (list e f fs g e e d cs cs a af g fs d d c b b) % (list 1 1 1 1 2 2 2 2 2 1 1 1 1 2 2 2 1 1) % (list te te te tq tq te tq tq th te te te tq tq te tq tq th) % % % second trumpet % (list c d ef e g g f e e r r r r r r r r r) % (list 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1) % (list te te te tq tq te tq tq th te te te tq tq te tq tq th) % )) %(setf stanza2 (list % (list g fs f e g c a c d g bf ef c ef f g r g g a g d c) % (list 1 1 1 1 1 2 1 2 2 1 1 2 2 2 2 2 2 2 2 2 2 2 2) % (list te te te te te te tq te tq te te te tq te tq tw tq te te te te tq te) % )) % %(let () % (setf tempo 100) % (play-stanza stanza1) % (play-stanza stanza2) % ) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Baby Elephant Walk % % from the Paramount Picture "HATARI" % (c) 1961, 1962, 1968 % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % melody; (setf stanza1 (list (list f a c f a g f d b c r f a c f a g f d) (list 2 2 3 3 3 3 3 3 2 3 0 2 2 3 3 3 3 3 3) (list tde ts1 te te te te te te te te tdh tde ts1 te te te te te te) %harmony; (list c gs a c gs a c gs a c c gs a c gs a c gs a) (list 1 0 0 1 0 0 1 0 0 1 1 0 0 1 0 0 1 0 0) (list tq te te tq te te tq te te te te te te tq te te tq te te) (list f gs a f gs a f gs a f f gs a f gs a f gs a) (list 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) (list tq te te tq te te tq te te te te te te tq te te tq te te) )) %melody; (setf stanza2 (list (list c d af d af f r) (list 3 3 2 3 2 2 0) (list tdh te (+ te tdh te) te te te tdh) %harmony; (list c c gs a c cs d f f cs d f f cs d f f cs d f f cs d) (list 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1) (list te te te te tq te te te te te te te te te te te te te te te te te te) (list f f gs a f cs d bf bf cs d bf bf cs d bf bf cs d bf bf cs d) (list 0 0 0 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1) (list te te te te tq te te te te te te te te te te te te te te te te te te) )) %melody; (setf stanza3 (list (list f a c f a g f d b c r r c g g e c r c) (list 2 2 3 3 3 3 3 3 2 3 0 0 3 3 3 3 3 0 3) (list tde ts1 te te te te te te te te th te te tq tq te te te te) %harmony; (list c gs a c gs a c gs a c c ds e g g ds e g g ds e) (list 1 0 0 1 0 0 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1) (list tq te te tq te te tq te te te te te te te te te te te te te te) (list f gs a f gs a f gs a f f ds e c c ds e c c ds e) (list 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1) (list tq te te tq te te tq te te te te te te te te te te te te te te) )) %melody; (setf stanza4 (list (list f f ef f ef c bf gs b b bf b bf af f c ef f) (list 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2) (list tq tq ts ts1 ts ts1 te te tq tq ts ts1 ts ts1 te te te te) %harmony; (list f f cs d f c c gs a c c) (list 1 1 1 1 1 1 1 0 0 1 1) (list te te te te th te te te te th tq) (list bf bf cs d bf f f gs a f f) (list 0 0 1 1 0 0 0 0 0 0 0) (list te te te te th te te te te th tq) )) (let () (setf octave-offset 0) (setf pitch-offset 0) (setf vol 10) (setf tempo 80) (play-stanza stanza1) (play-stanza stanza2) (play-stanza stanza3) (play-stanza stanza4) ) (setf stanza-counter 0) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % generate C structures to play the tune; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% (de print-stanza (stanza stanza-name) (let ((notes nil) (octaves nil) (durations nil) (voice-names (make-vector 3 "NULL")) (voice-num 0) ) (while stanza (vector-store voice-names voice-num (bldmsg "&voice%d" stanza-counter)) (setf notes (first stanza)) (setf octaves (second stanza)) (setf durations (third stanza)) (setf stanza (pnth stanza 4)) (printf "int notes%d[] =%n {" stanza-counter) (for (in i notes) (do (printf "%d," i) )) (printf "-42};%n") (printf "int octaves%d[] =%n {" stanza-counter) (for (in i octaves) (do (printf "%d," i) )) (printf "-42};%n") (printf "int durations%d[] =%n {" stanza-counter) (for (in i durations) (do (printf "%d," i) )) (printf "-42};%n") (printf "struct voice_def voice%d = { notes%d, octaves%d, durations%d};%n" stanza-counter stanza-counter stanza-counter stanza-counter); (setf stanza-counter (+ stanza-counter 1)) (setf voice-num (+ voice-num 1)) ) (printf "struct stanza_def %s = { %s, %s, %s, %s};%n" stanza-name (vector-fetch voice-names 0) (vector-fetch voice-names 1) (vector-fetch voice-names 2) (vector-fetch voice-names 3)) )) % (in-package old-package) @//E*O*F dbsetup.sl// chmod u=rw,g=rw,o=r dbsetup.sl echo x - music.c sed 's/^@//' > "music.c" <<'@//E*O*F music.c//' #include <stdio.h> #define tempo 80 struct voice_def { int *notes; int *octaves; int *durations; }; struct stanza_def { struct voice_def *voice1; struct voice_def *voice2; struct voice_def *voice3; struct voice_def *voice4; }; struct voice_task { int time_to_go; int voice_num; int *notes; int *octaves; int *durations; }; #include "mytune.h" int vol = 11; int octave_offset = 0; int pitch_offset = 0; int scale[12][6] = { 0, 386, 705, 864, 943, 984, 0, 422, 722, 873, 948, 0, 0, 456, 739, 881, 952, 0, 0, 487, 755, 889, 956, 0, 12, 518, 770, 897, 960, 0, 69, 546, 784, 904, 963, 0, 123, 573, 798, 911, 967, 0, 173, 598, 810, 916, 970, 0, 220, 622, 822, 922, 973, 0, 266, 645, 834, 928, 976, 0, 308, 665, 844, 933, 978, 0, 348, 685, 854, 938, 981, 0}; beep_or_noise_duration_left(val) int val; { beep_or_noise_left(val); } get_note(pitch,octave) int pitch,octave; { int real_pitch; int real_octave; real_pitch = pitch + pitch_offset; real_octave = octave + octave_offset; if (real_pitch >= 12) { real_pitch = real_pitch - 12; real_octave = real_octave + 1; } if (real_pitch < 0) { real_pitch = real_pitch + 12; real_octave = real_octave - 1; } return(scale[real_pitch][real_octave]); } note(pitch, octave, voice, duration) int pitch, octave, voice, duration; { if (pitch == -1) beep(voice,0,0,(10 * duration)/tempo); else beep(voice, get_note(pitch,octave), vol, (10 * duration)/tempo); } go_on_voice(voice_num) int voice_num; { while(beep_or_noise_duration_left(voice_num)) ; } load_voice(task,data,voice_num) struct voice_task *task; struct voice_def *data; int voice_num; { if (data == NULL) (*task).time_to_go = -1; else { (*task).time_to_go = 0; (*task).voice_num = voice_num; (*task).notes = (*data).notes; (*task).octaves = (*data).octaves; (*task).durations = (*data).durations; } } play_stanza(stanza) struct stanza_def *stanza; { struct voice_def *voice1,*voice2,*voice3,*voice4; struct voice_task voices[4]; int num_voices, note_id, octave, voice_num, duration, wait_time; int i,j; /** load up the voice task structures **/ load_voice(&voices[0],(*stanza).voice1,1); load_voice(&voices[1],(*stanza).voice2,2); load_voice(&voices[2],(*stanza).voice3,3); load_voice(&voices[3],(*stanza).voice4,4); /** how many voices do we have data for? **/ for (i=0; i<4; i++) if (voices[i].time_to_go == -1) break; num_voices = i; /** while we still have some voices to give data to **/ while (num_voices > 0) { /** find voices that are ready for another note **/ for (i=0; i<num_voices; i++) if (voices[i].time_to_go == 0) { note_id = *(voices[i].notes++); octave = *(voices[i].octaves++); duration = *(voices[i].durations++); voice_num = voices[i].voice_num; note(note_id, octave, voice_num, duration); voices[i].time_to_go = duration; } /** find the task with the shortest time and we'll decrement **/ /** the other tasks by its time and wait on it; **/ wait_time = 10000; for (i=0; i<num_voices; i++) if (voices[i].time_to_go < wait_time) { wait_time = voices[i].time_to_go; voice_num = voices[i].voice_num; } /** update the time of all tasks **/ for (i=0; i<num_voices; i++) voices[i].time_to_go -= wait_time; /** wait on the voice that will be done first **/ go_on_voice(voice_num); /** remove voices with no more notes; **/ i = 0; while(i < num_voices) { if (*(voices[i].notes) == -42) { /** delete voice # i **/ for (j=i; j<num_voices-1; j++) voices[j] = voices[j+1]; num_voices--; } else i++; } } } main() { play_stanza(&stanza1); play_stanza(&stanza2); play_stanza(&stanza3); play_stanza(&stanza4); } @//E*O*F music.c// chmod u=rw,g=rw,o=r music.c echo x - beeper.c sed 's/^@//' > "beeper.c" <<'@//E*O*F beeper.c//' /* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; File: beeper.c ; SCCS: %A% %G% %U% ; Description: Access Gator/Bobcat beeper ; Created: 2-Aug-85 ; Modified: 7-Aug-85 17:00:34 ; Language: C ; Package: PSL ; Status: Experimental (Do Not Distribute) ; ; (c) Copyright 1985, Hewlett-Packard Company, all rights reserved. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */ /* Public functions: beep noise beep_or_noise_left We offer three voices and a noise source. Each sound is controllable in pitch, volume and duration. Pitch goes from 0 to 1023, volume goes from 0 to 15, duration is between 0 and 255 10msec intervalls. A duration of 0 turns the voice on continuously. A volume of 0 turns it off. The manufacturing specs give details on the programming interface. Here is a summary: The beeper is accessed through ioctl calls. The request argument is either "Send data to beeper" or "Read voice values from beeper". The argument is a pointer to a 4 byte buffer. These four bytes are defined here. R0-R3: Register address field. In the order R2, R1, R0: 0 0 0: Voice 1 frequency 0 0 1: Voice 1 attenuation 0 1 0: Voice 2 frequency 0 1 1: Voice 2 attenuation 1 0 0: Voice 3 frequency 1 0 1: Voice 3 attenuation 1 1 0: Noise control 1 1 1: Noise attentuation F0-F9: 10 bits pitch A0-A3: Attenuation D0-D7: Duration in 10msec's The placement of data in the buffer is a bit srewy: Byte 0 (Frequency 1): 1 R2 R1 R0 F3 F2 F1 F0 LSB Byte 1(Frequency 2): 0 0 F9 F8 F7 F6 F5 F4 Byte 2 (Attenuator) : 1 R2 R1 R0 A3 A2 A1 A0 Byte 3 (Duration) : D7 D6 D5 D4 D3 D2 D1 D0 The volume is inversely proportional to the attenuation. In order to provide rising numbers for rising loudness to the user, we expect a volume and modify to get the attenuation. The same goes for the pitch. In order to calculate frequency of the pitch, use: 83333/(pitch-1023) It is possible at any time to request the time any voice has left to run. This is done by: F4: Read voice1 timer F5: Read voice2 timer F6: Read voice3 timer F7: Read voice4 timer (noise) Noise is generated using a shift register. The following controls are possible for noise: - Attenuation - Duration - Periodic or white noise - 3 shift rates or output of voice 4 as shift rate Bytes 0 and 1 of the data buffer must both have identical contents to control the noise. Attenuation and duration are as in the other voices. Bytes 0 and 1 should look like this: 1 R2 R1 R0 0 FB NF1 NF0 LSB R2, R1 and R0 must be 1, 1 and 0. If FB is 0, periodic noise is generated. If FB is 1, white noise is produced. NF1 and NF2 control the shift rate of the noise generator: NF1 NF2 Shift Rate -------------------------- 0 0 M/64 0 1 M/128 1 0 M/256 1 1 Uses tone generator 3 output M is related to the clock rate. The voice start routines return 0 if all is well, -1 if we had trouble accessing the device file for the beeper and -2 if given parameters were out of range: */ #include <fcntl.h> #include <sys/hilioctl.h> /********************************************************************* *DEFINES: * *********************************************************************/ #define ALL_OK 0 #define ACCESS_PROBLEM -1 #define BAD_RANGE -2 #define BEEPER_DEVICE "/dev/rhil" #define VOICE1_FREQ_REG 0x80 /* Top nibbles for byte0 for all voices: */ #define VOICE2_FREQ_REG 0xA0 #define VOICE3_FREQ_REG 0xC0 #define NOISE_FREQ_REG 0xE0 #define VOICE1_VOL_REG 0x90 /* Top nibbles for byte2 for all voices: */ #define VOICE2_VOL_REG 0xB0 #define VOICE3_VOL_REG 0xD0 #define NOISE_VOL_REG 0xF0 #define MIN_VOICE 1 /* Legal ranges for parms from user: */ #define MAX_VOICE 3 #define MIN_PITCH 0 #define MAX_PITCH 1023 #define MIN_DURATION 0 #define MAX_DURATION 255 #define MIN_VOLUME 0 #define MAX_VOLUME 15 #define MIN_TYPE 0 #define MAX_TYPE 1 #define MIN_RATE 0 #define MAX_RATE 3 static int beeper_fd = -1; /********************************************************************* * PUBLIC FUNCTIONS: * *********************************************************************/ /***************************************************************************** * * * Beep using specified voice: * * * * TAKES: * * * * VOICE : from 1 to 3 * * PITCH : from 0 to 1023 (incl) * * VOLUME : from 0 to 15 (incl). Zero turns voice off. * * DURATION : from 0 to 255 (incl). Zero turns voice on continuously. * * * * RETURNS: * * * * 0 : All ok * * -1 : Cannot access beeper device file * * -2 : Parameter out of range * * * ******************************************************************************/ beep(voice,pitch,volume,duration) int voice,pitch,volume,duration; { unsigned char buffer[4]; /* Check ranges of parameters: */ if ( (voice < MIN_VOICE) || (voice > MAX_VOICE) || (pitch < MIN_PITCH) || (pitch > MAX_PITCH) || (volume < MIN_VOLUME) || (volume > MAX_VOLUME) || (duration < MIN_DURATION) || (duration > MAX_DURATION) ) return(BAD_RANGE); /* Check whether beeper device has already been opened: */ if (beeper_fd < 0) if ((beeper_fd = open(BEEPER_DEVICE,O_RDWR)) < 0) return(ACCESS_PROBLEM); /* Init the voice dependent data bytes. Note the inversion of user's volume and pitch specs to attenuation: */ volume = MAX_VOLUME - volume; pitch = MAX_PITCH - pitch; switch (voice) { case 1: buffer[0] = VOICE1_FREQ_REG | (pitch & 0x0000000f); buffer[2] = VOICE1_VOL_REG | (volume & 0x0000000f); break; case 2: buffer[0] = VOICE2_FREQ_REG | (pitch & 0x0000000f); buffer[2] = VOICE2_VOL_REG | (volume & 0x0000000f); break; case 3: buffer[0] = VOICE3_FREQ_REG | (pitch & 0x0000000f); buffer[2] = VOICE3_VOL_REG | (volume & 0x0000000f); break; }; /* The high 6 bits of the pitch go into byte 1: */ buffer[1] = 0x0000003f & (pitch >> 4); /* Duration: */ buffer[3] = duration; if (ioctl(beeper_fd,EFTSBP,buffer) < 0) return(ACCESS_PROBLEM); return(ALL_OK); } /* end function beep */ /*----------------------------------------------------*/ /****************************************************************************** * Produce noise. * * * * TAKES: * * * * TYPE : from 0 to 1. 0 is periodic noise. 1 is white noise. * * RATE : from 0 to 3. 0 is M/64. 1 is M/128. 2 is M/256. 3 means rate * * determined by output of voice 3. * * VOLUME : from 0 to 15 (incl). Zero turns voice off. * * DURATION : from 0 to 255 (incl). Zero turns voice on continuously. * * * * RETURNS: * * * * 0 : All ok * * -1 : Cannot access beeper device file * * -2 : Parameter out of range * ******************************************************************************/ noise(type,rate,volume,duration) int type,rate,volume,duration; { unsigned char buffer[4]; /* Check ranges of parameters: */ if ( (type < MIN_TYPE) || (type > MAX_TYPE) || (rate < MIN_RATE) || (rate > MAX_RATE) || (volume < MIN_VOLUME) || (volume > MAX_VOLUME) || (duration < MIN_DURATION) || (duration > MAX_DURATION) ) return(BAD_RANGE); /* Check whether beeper device has already been opened: */ if (beeper_fd < 0) if ((beeper_fd = open(BEEPER_DEVICE,O_RDWR)) < 0) return(ACCESS_PROBLEM); /* Invert the volume provided by the user getting the attenuation: */ volume = MAX_VOLUME - volume; type = type << 2; buffer[0] = NOISE_FREQ_REG | (type | rate); /* Byte one must be identical to byte 0: */ buffer[1] = buffer[0]; buffer[2] = NOISE_VOL_REG | (volume & 0x0000000f); buffer[3] = duration; if (ioctl(beeper_fd,EFTSBP,buffer) < 0) return(ACCESS_PROBLEM); return(ALL_OK); } /* end function noise */ /*----------------------------------------------------*/ /**************************************************************************** * * * Read how many 10msec intervalls are left till a voice has * * beeped to the end. This routine is good for noise also. * * * * TAKES: * * * * voice : from 1 to 4 * * * * RETURNS: * * * * 0 : Beeper has finished * * >0 : Number of 10msec intervalls * * -1 : Cannot access beeper device file * * -2 : Parameter out of range * *****************************************************************************/ beep_or_noise_left(voice) int voice; { unsigned char buffer[4]; /* Check for legal parameter range. The '+1' is to include noise generator: */ if ( (voice < MIN_VOICE) || (voice > (MAX_VOICE + 1)) ) return(BAD_RANGE); /* Check whether beeper device has already been opened: */ if (beeper_fd < 0) if ((beeper_fd = open(BEEPER_DEVICE,O_RDWR)) < 0) return(ACCESS_PROBLEM); /* Get the timer values into the buffer bytes: */ if (ioctl(beeper_fd,EFTRT,buffer) < 0) return(ACCESS_PROBLEM); return((int) buffer[voice-1]); } /* end function beep_or_noise_left */ /*---------------------------------------------------*/ @//E*O*F beeper.c// chmod u=rw,g=rw,o=r beeper.c echo x - mytune.h sed 's/^@//' > "mytune.h" <<'@//E*O*F mytune.h//' int notes0[] = {5,9,0,5,9,7,5,2,11,0,-1,5,9,0,5,9,7,5,2,-42}; int octaves0[] = {2,2,3,3,3,3,3,3,2,3,0,2,2,3,3,3,3,3,3,-42}; int durations0[] = {187,63,125,125,125,125,125,125,125,125,750,187,63,125,125,125,125,125,125,-42}; struct voice_def voice0 = { notes0, octaves0, durations0}; int notes1[] = {0,8,9,0,8,9,0,8,9,0,0,8,9,0,8,9,0,8,9,-42}; int octaves1[] = {1,0,0,1,0,0,1,0,0,1,1,0,0,1,0,0,1,0,0,-42}; int durations1[] = {250,125,125,250,125,125,250,125,125,125,125,125,125,250,125,125,250,125,125,-42}; struct voice_def voice1 = { notes1, octaves1, durations1}; int notes2[] = {5,8,9,5,8,9,5,8,9,5,5,8,9,5,8,9,5,8,9,-42}; int octaves2[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-42}; int durations2[] = {250,125,125,250,125,125,250,125,125,125,125,125,125,250,125,125,250,125,125,-42}; struct voice_def voice2 = { notes2, octaves2, durations2}; struct stanza_def stanza1 = { &voice0, &voice1, &voice2, NULL}; int notes3[] = {0,2,8,2,8,5,-1,-42}; int octaves3[] = {3,3,2,3,2,2,0,-42}; int durations3[] = {750,125,1000,125,125,125,750,-42}; struct voice_def voice3 = { notes3, octaves3, durations3}; int notes4[] = {0,0,8,9,0,1,2,5,5,1,2,5,5,1,2,5,5,1,2,5,5,1,2,-42}; int octaves4[] = {1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,-42}; int durations4[] = {125,125,125,125,250,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,-42}; struct voice_def voice4 = { notes4, octaves4, durations4}; int notes5[] = {5,5,8,9,5,1,2,10,10,1,2,10,10,1,2,10,10,1,2,10,10,1,2,-42}; int octaves5[] = {0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,-42}; int durations5[] = {125,125,125,125,250,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,-42}; struct voice_def voice5 = { notes5, octaves5, durations5}; struct stanza_def stanza2 = { &voice3, &voice4, &voice5, NULL}; int notes6[] = {5,9,0,5,9,7,5,2,11,0,-1,-1,0,7,7,4,0,-1,0,-42}; int octaves6[] = {2,2,3,3,3,3,3,3,2,3,0,0,3,3,3,3,3,0,3,-42}; int durations6[] = {187,63,125,125,125,125,125,125,125,125,500,125,125,250,250,125,125,125,125,-42}; struct voice_def voice6 = { notes6, octaves6, durations6}; int notes7[] = {0,8,9,0,8,9,0,8,9,0,0,3,4,7,7,3,4,7,7,3,4,-42}; int octaves7[] = {1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,-42}; int durations7[] = {250,125,125,250,125,125,250,125,125,125,125,125,125,125,125,125,125,125,125,125,125,-42}; struct voice_def voice7 = { notes7, octaves7, durations7}; int notes8[] = {5,8,9,5,8,9,5,8,9,5,5,3,4,0,0,3,4,0,0,3,4,-42}; int octaves8[] = {0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,-42}; int durations8[] = {250,125,125,250,125,125,250,125,125,125,125,125,125,125,125,125,125,125,125,125,125,-42}; struct voice_def voice8 = { notes8, octaves8, durations8}; struct stanza_def stanza3 = { &voice6, &voice7, &voice8, NULL}; int notes9[] = {5,5,3,5,3,0,10,8,11,11,10,11,10,8,5,0,3,5,-42}; int octaves9[] = {3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,-42}; int durations9[] = {250,250,62,63,62,63,125,125,250,250,62,63,62,63,125,125,125,125,-42}; struct voice_def voice9 = { notes9, octaves9, durations9}; int notes10[] = {5,5,1,2,5,0,0,8,9,0,0,-42}; int octaves10[] = {1,1,1,1,1,1,1,0,0,1,1,-42}; int durations10[] = {125,125,125,125,500,125,125,125,125,500,250,-42}; struct voice_def voice10 = { notes10, octaves10, durations10}; int notes11[] = {10,10,1,2,10,5,5,8,9,5,5,-42}; int octaves11[] = {0,0,1,1,0,0,0,0,0,0,0,-42}; int durations11[] = {125,125,125,125,500,125,125,125,125,500,250,-42}; struct voice_def voice11 = { notes11, octaves11, durations11}; struct stanza_def stanza4 = { &voice9, &voice10, &voice11, NULL}; @//E*O*F mytune.h// chmod u=rw,g=rw,o=r mytune.h exit 0 -- See above (214)661-8960
jpederse@encad.Wichita.NCR.COM (John Pedersen) (02/20/88)
If you don't get responses to this posting I will E-Mail the fantastic responses that I got. Should keep the HP musical for some time to come. -- John Pedersen
fritz@hpfclp.HP.COM (Gary Fritz) (02/20/88)
Well, I've gotten 4 requests in the past 24 hours, so I guess it's worth posting: ************************************************************************ Here's the info on the s300 sound generators. I take no credit for any of this, and have never spent time to learn how it works, so I can't help you if you have any trouble with it. Caveat emptor! Some of the source is written in PSL (Portable Standard Lisp), but you could probably translate it to Common Lisp or C or whatever without too much trouble. Enjoy, Gary Fritz fritz%hpfclp@hplabs.hp.com : # # # For those who may not know, the beeper on gators/bobcats have # four independent voices. Three of these have a programmable tone, # and the fouth is a noise generator. # # This shar contains some low level code to talk to the beeper. # There is also some PSL (Portable Standard Lisp) code that allows you # to write music in an easy to read format (See example in the file # dbsetup.sl). More recently, these functions were translated into C # and a function was written that would take the lisp lists and generate # C data structures that could be interpreted by the C code. # # If you can run PSL, you should be able to write music immediately. # Anyone can build the example C program and hear what the machine can do. # Perhaps someone without PSL will be inspired to write a nicer front end. # # # THIS CODE IS PROVIDED WITHOUT WARRANTEES OF ANY KIND. NO SUPPORT # IS PROVIDED OR IMPLIED. HEWLETT-PACKARD COMPANY ACCEPTS NO RESPONSIBILITY # FOR ANY USE OF THIS CODE. # # Other than that, enjoy yourself! :-) # # # # 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 on Wed Dec 18 15:28:16 PST 1985 # Contents: Makefile dbsetup.sl music.c beeper.c mytune.h echo "x - beeper.doc" sed -e 's/^X//' > beeper.doc << '//E*O*F beeper.doc//' From: tgl@zog.cs.cmu.edu (Tom Lane) Date: Wed, 22 Apr 87 17:47:14 MST Organization: Carnegie-Mellon University, CS/RI Newsgroups: comp.sys.hp In <1365@ucbcad.berkeley.edu> chris@ic.uucp (Chris Guthrie) writes: >We spent last night playing with the tone generator on our 320s. >Although we were able to get a number of unique and interesting >noises out of them, we couldn't figure out the layout of the >four bytes in the EFTSBP ioctl command (other than the volume and >timer bits). Can anyone post the layout of these bytes. Thanks! This may not be too accurate 'cuz its based on old documentation (pre-Series 300) for a different operating system (HP Pascal), but it's worth a try. What you have is a TI SN76494 4-voice sound generator; it can make 3 independent square waves plus a noise source. To control one of the square wave voices, the format of the 4 bytes is: byte 1: 1 v1 v0 0 f3 f2 f1 f0 byte 2: 0 0 f9 f8 f7 f6 f5 f4 byte 3: 1 v1 v0 1 a3 a2 a1 a0 byte 4: d7 d6 d5 d4 d3 d2 d1 d0 where v1-v0 is the voice number (00,01, or 10); f9..f0 is a 10-bit value defining the frequency; a3..a0 is a 4-bit value defining the attenuation (volume); d7..d0 is an 8-bit value defining the duration of the tone. Note that the voice number must be given in two places. The f9..f0 value should be 83333 / (desired freq. in Hz); the a3..a0 value is 0 (maximum volume) to 15 (off), in steps of about 2 dB; the d7..d0 value is duration in 10-msec units, or 0 to sound until a countermanding command is given. For the noise source, the command format is: byte 1: 1 1 1 0 0 fb n1 n0 byte 2: 1 1 1 0 0 fb n1 n0 (i.e. same as byte 1) byte 3: 1 1 1 1 a3 a2 a1 a0 byte 4: d7 d6 d5 d4 d3 d2 d1 d0 (thus, the voice number is "11") where: fb is 0 for "periodic" noise and 1 for white noise; n1-n0 control the "noise generator shift rate" as follows: 00 333333/64 Hz 01 333333/128 Hz 10 333333/256 Hz 11 Use voice "10"'s output (don't ask me what any of that means). The attenuation and duration are the same as for the other sources. Somebody please check this out and let the net know if it's OK... I don't run HP/UX. tom lane ----- ARPA: lane@ZOG.CS.CMU.EDU UUCP: ...!seismo!zog.cs.cmu.edu!lane BITNET: lane%zog.cs.cmu.edu@cmuccvma //E*O*F beeper.doc// chmod 666 beeper.doc echo x - Makefile sed 's/^@//' > "Makefile" <<'@//E*O*F Makefile//' it: music music.o: music.c mytune.h cc -c music.c beeper.o: beeper.c cc -c beeper.c music: music.o beeper.o cc -o music music.o beeper.o shar: shar -c Makefile dbsetup.sl music.c beeper.c mytune.h > music.shar @//E*O*F Makefile// chmod u=rw,g=rw,o=rw Makefile echo x - dbsetup.sl sed 's/^@//' > "dbsetup.sl" <<'@//E*O*F dbsetup.sl//' %Get Compiled C code (lisp:load-ofile "/usr/local/src/nmode/beeper/beeper.o" :libs "") (lisp:ff beep "_beep" :parms (nil nil nil nil)) (lisp:ff noise "_noise" :parms (nil nil nil nil)) (lisp:ff beep-or-noise-duration-left "_beep_or_noise_left" :parms (nil)) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Set up tempo variable and note values %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % (when (null (find-package "music")) % (make-package "music")) % % (setf music::old-package *package*) % (in-package 'music) % % (import 'pnth (find-package "music")) (setf tempo 100) (setf whole 1000) (setf half (/ whole 2)) (setf quarter (/ half 2)) (setf eighth (/ quarter 2)) (setf sixteenth (/ eighth 2)) (setf thirtysecond (/ sixteenth 2)) (setf dot-quarter (+ quarter eighth)) (setf dot-half (+ half quarter)) (setf dot-eighth (+ eighth sixteenth)) (setf triplet (/ quarter 3)) (setf rest -1) (setf r -1) (setf C 0) (setf C-sharp 1) (setf cs 1) (setf D 2) (setf ds 3) (setf E-flat 3) (setf Ef 3) (setf E 4) (setf F 5) (setf F-sharp 6) (setf Fs 6) (setf G 7) (setf G-sharp 8) (setf Gs 8) (setf A-flat 8) (setf Af 8) (setf A 9) (setf B-flat 10) (setf Bf 10) (setf B 11) (setf tw whole) (setf th half) (setf tq quarter) (setf te eighth) (setf ts sixteenth) (setf ts1 (+ ts 1)) (setf tdh dot-half) (setf tdq dot-quarter) (setf tde dot-eighth) (setf tt triplet) (setf scale % (vector % (vector 1 510 770 896 959 992) % (vector 50 540 784 902 962 994) % (vector 100 570 798 909 966 996) % (vector 150 600 811 914 970 998) % (vector 200 630 823 922 973 999) % (vector 250 650 837 928 975 1000) % (vector 300 670 849 934 978 1001) % (vector 350 690 857 939 981 1002) % (vector 390 710 866 945 984 1003) % (vector 420 723 874 950 986 1004) % (vector 450 740 882 953 988 1005) % (vector 480 760 891 956 990 1006) % ) (vector (vector 0 386 705 864 943 984)% c (vector 0 422 722 873 948 0) % c# (vector 0 456 739 881 952 0) % d (vector 0 487 755 889 956 0) % d# (vector 12 518 770 897 960 0) % e (vector 69 546 784 904 963 0) % f (vector 123 573 798 911 967 0) % f# (vector 173 598 810 916 970 0) % g (vector 220 622 822 922 973 0) % g# (vector 266 645 834 928 976 0) % a (vector 308 665 844 933 978 0) % a# (vector 348 685 854 938 981 0) % b ) ) (de get-note (pitch octave) (let ((real-pitch (+ pitch pitch-offset)) (real-octave (+ octave octave-offset)) ) (when (>= real-pitch 12) (setf real-pitch (- real-pitch 12)) (setf real-octave (+ real-octave 1)) ) (when (< real-pitch 0) (setf real-pitch (+ real-pitch 12)) (setf real-octave (- real-octave 1)) ) (vector-fetch (vector-fetch scale real-pitch) real-octave) )) % (de get-note (pitch octave) % (vector-fetch (vector-fetch scale pitch) octave) % ) (de note (pitch octave voice duration) (if (eq pitch -1) % it is a rest; (beep voice 0 0 (/ (* 10 duration) tempo)) % otherwise; (beep voice (get-note pitch octave) vol (/ (* 10 duration) tempo)) )) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Set-up Musical Environment %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% (setq vol 11) % Volume Setting (setf octave-offset 0) (setf pitch-offset 0) %Last note finished, now go on (defun go-on () (repeat (beep-or-noise-duration-left 1) (= (beep-or-noise-duration-left 1) 0)) ) (defun go-on-voice (voice-num) (repeat (beep-or-noise-duration-left voice-num) (= (beep-or-noise-duration-left voice-num) 0)) ) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Music structure: % % For each voice, there are parallel lists for the notes, the octaves, % and the times; % % A stanza is a list of either 3,6,9,or 12 lists; (depending on how many % voices you use; % % sample stanza: % % (setf stanza % (list (list a b b-flat f-sharp) % (list 1 1 2 1 ) % (list whole whole half quarter) % % (list a b b-flat g ) % (list 2 2 3 2 ) % (list whole whole half quarter) % ) % ) % % Music task structure: % % [ element # % time-to-go 0 % voice-num 1 % ( notes ) 2 % ( octave ) 3 % ( time ) 4 % ] % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% (defun play-stanza (stanza) (let ((time-to-go-idx 0) (voice-num-idx 1) (notes-idx 2) (octaves-idx 3) (times-idx 4) (queue nil) (voice-num nil) (wait-time nil) (temp nil) ) % translate music symbols to numbers; % (for (in list stanza) (do % (for (on i list) (do % (when (null (numberp (car i))) % (setf (car i) (cdr (assoc (car i) music-symbols))) % ) % )) % )) % build a task for each voice; (setf voice-num 1) (while stanza (push (vector 0 voice-num (first stanza) (second stanza) (third stanza) ) queue) (setf voice-num (+ voice-num 1)) (setf stanza (pnth stanza 4)) ) % while there are voices to be played; (while queue % give more data to voices that are ready; (for (in task queue) (with notes octaves times time-to-go) (do % a voice ready for another note; (when (eq 0 (vector-fetch task time-to-go-idx)) (setf notes (vector-fetch task notes-idx)) (setf octaves (vector-fetch task octaves-idx)) (setf times (vector-fetch task times-idx)) (setf time-to-go (first times)) % play a note on this voice; (note (first notes) (first octaves) (vector-fetch task voice-num-idx) time-to-go) (vector-store task time-to-go-idx time-to-go) (vector-store task octaves-idx (rest octaves)) (vector-store task times-idx (rest times)) (vector-store task notes-idx (rest notes)) ) )) % find the task with the shortest time and we'll decrement % the other tasks by its time and wait on it; (setf wait-time 10000) (for (in task queue) (do (when (< (setf temp (vector-fetch task time-to-go-idx)) wait-time) (setf wait-time temp) (setf voice-num (vector-fetch task voice-num-idx)) ) )) % update the time of all tasks; (for (in task queue) (do (vector-store task time-to-go-idx (- (vector-fetch task time-to-go-idx) wait-time) ) )) % wait on the voice that will be done first; (go-on-voice voice-num) % remove voices with no more notes; (setf temp queue) (for (in task temp) (do (when (null (vector-fetch task notes-idx)) (setf queue (delete task queue)) ) )) ) )) % end of function play-stanza; % (setf stanza1 (list % % first trumpet % (list e f fs g e e d cs cs a af g fs d d c b b) % (list 1 1 1 1 2 2 2 2 2 1 1 1 1 2 2 2 1 1) % (list te te te tq tq te tq tq th te te te tq tq te tq tq th) % % % second trumpet % (list c d ef e g g f e e r r r r r r r r r) % (list 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1) % (list te te te tq tq te tq tq th te te te tq tq te tq tq th) % )) %(setf stanza2 (list % (list g fs f e g c a c d g bf ef c ef f g r g g a g d c) % (list 1 1 1 1 1 2 1 2 2 1 1 2 2 2 2 2 2 2 2 2 2 2 2) % (list te te te te te te tq te tq te te te tq te tq tw tq te te te te tq te) % )) % %(let () % (setf tempo 100) % (play-stanza stanza1) % (play-stanza stanza2) % ) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Baby Elephant Walk % % from the Paramount Picture "HATARI" % (c) 1961, 1962, 1968 % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % melody; (setf stanza1 (list (list f a c f a g f d b c r f a c f a g f d) (list 2 2 3 3 3 3 3 3 2 3 0 2 2 3 3 3 3 3 3) (list tde ts1 te te te te te te te te tdh tde ts1 te te te te te te) %harmony; (list c gs a c gs a c gs a c c gs a c gs a c gs a) (list 1 0 0 1 0 0 1 0 0 1 1 0 0 1 0 0 1 0 0) (list tq te te tq te te tq te te te te te te tq te te tq te te) (list f gs a f gs a f gs a f f gs a f gs a f gs a) (list 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) (list tq te te tq te te tq te te te te te te tq te te tq te te) )) %melody; (setf stanza2 (list (list c d af d af f r) (list 3 3 2 3 2 2 0) (list tdh te (+ te tdh te) te te te tdh) %harmony; (list c c gs a c cs d f f cs d f f cs d f f cs d f f cs d) (list 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1) (list te te te te tq te te te te te te te te te te te te te te te te te te) (list f f gs a f cs d bf bf cs d bf bf cs d bf bf cs d bf bf cs d) (list 0 0 0 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1) (list te te te te tq te te te te te te te te te te te te te te te te te te) )) %melody; (setf stanza3 (list (list f a c f a g f d b c r r c g g e c r c) (list 2 2 3 3 3 3 3 3 2 3 0 0 3 3 3 3 3 0 3) (list tde ts1 te te te te te te te te th te te tq tq te te te te) %harmony; (list c gs a c gs a c gs a c c ds e g g ds e g g ds e) (list 1 0 0 1 0 0 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1) (list tq te te tq te te tq te te te te te te te te te te te te te te) (list f gs a f gs a f gs a f f ds e c c ds e c c ds e) (list 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1) (list tq te te tq te te tq te te te te te te te te te te te te te te) )) %melody; (setf stanza4 (list (list f f ef f ef c bf gs b b bf b bf af f c ef f) (list 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2) (list tq tq ts ts1 ts ts1 te te tq tq ts ts1 ts ts1 te te te te) %harmony; (list f f cs d f c c gs a c c) (list 1 1 1 1 1 1 1 0 0 1 1) (list te te te te th te te te te th tq) (list bf bf cs d bf f f gs a f f) (list 0 0 1 1 0 0 0 0 0 0 0) (list te te te te th te te te te th tq) )) (let () (setf octave-offset 0) (setf pitch-offset 0) (setf vol 10) (setf tempo 80) (play-stanza stanza1) (play-stanza stanza2) (play-stanza stanza3) (play-stanza stanza4) ) (setf stanza-counter 0) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % generate C structures to play the tune; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% (de print-stanza (stanza stanza-name) (let ((notes nil) (octaves nil) (durations nil) (voice-names (make-vector 3 "NULL")) (voice-num 0) ) (while stanza (vector-store voice-names voice-num (bldmsg "&voice%d" stanza-counter)) (setf notes (first stanza)) (setf octaves (second stanza)) (setf durations (third stanza)) (setf stanza (pnth stanza 4)) (printf "int notes%d[] =%n {" stanza-counter) (for (in i notes) (do (printf "%d," i) )) (printf "-42};%n") (printf "int octaves%d[] =%n {" stanza-counter) (for (in i octaves) (do (printf "%d," i) )) (printf "-42};%n") (printf "int durations%d[] =%n {" stanza-counter) (for (in i durations) (do (printf "%d," i) )) (printf "-42};%n") (printf "struct voice_def voice%d = { notes%d, octaves%d, durations%d};%n" stanza-counter stanza-counter stanza-counter stanza-counter); (setf stanza-counter (+ stanza-counter 1)) (setf voice-num (+ voice-num 1)) ) (printf "struct stanza_def %s = { %s, %s, %s, %s};%n" stanza-name (vector-fetch voice-names 0) (vector-fetch voice-names 1) (vector-fetch voice-names 2) (vector-fetch voice-names 3)) )) % (in-package old-package) @//E*O*F dbsetup.sl// chmod u=rw,g=rw,o=rw dbsetup.sl echo x - music.c sed 's/^@//' > "music.c" <<'@//E*O*F music.c//' #include <stdio.h> #define tempo 80 struct voice_def { int *notes; int *octaves; int *durations; }; struct stanza_def { struct voice_def *voice1; struct voice_def *voice2; struct voice_def *voice3; struct voice_def *voice4; }; struct voice_task { int time_to_go; int voice_num; int *notes; int *octaves; int *durations; }; #include "mytune.h" int vol = 11; int octave_offset = 0; int pitch_offset = 0; int scale[12][6] = { 0, 386, 705, 864, 943, 984, 0, 422, 722, 873, 948, 0, 0, 456, 739, 881, 952, 0, 0, 487, 755, 889, 956, 0, 12, 518, 770, 897, 960, 0, 69, 546, 784, 904, 963, 0, 123, 573, 798, 911, 967, 0, 173, 598, 810, 916, 970, 0, 220, 622, 822, 922, 973, 0, 266, 645, 834, 928, 976, 0, 308, 665, 844, 933, 978, 0, 348, 685, 854, 938, 981, 0}; beep_or_noise_duration_left(val) int val; { beep_or_noise_left(val); } get_note(pitch,octave) int pitch,octave; { int real_pitch; int real_octave; real_pitch = pitch + pitch_offset; real_octave = octave + octave_offset; if (real_pitch >= 12) { real_pitch = real_pitch - 12; real_octave = real_octave + 1; } if (real_pitch < 0) { real_pitch = real_pitch + 12; real_octave = real_octave - 1; } return(scale[real_pitch][real_octave]); } note(pitch, octave, voice, duration) int pitch, octave, voice, duration; { if (pitch == -1) beep(voice,0,0,(10 * duration)/tempo); else beep(voice, get_note(pitch,octave), vol, (10 * duration)/tempo); } go_on_voice(voice_num) int voice_num; { while(beep_or_noise_duration_left(voice_num)) ; } load_voice(task,data,voice_num) struct voice_task *task; struct voice_def *data; int voice_num; { if (data == NULL) (*task).time_to_go = -1; else { (*task).time_to_go = 0; (*task).voice_num = voice_num; (*task).notes = (*data).notes; (*task).octaves = (*data).octaves; (*task).durations = (*data).durations; } } play_stanza(stanza) struct stanza_def *stanza; { struct voice_def *voice1,*voice2,*voice3,*voice4; struct voice_task voices[4]; int num_voices, note_id, octave, voice_num, duration, wait_time; int i,j; /** load up the voice task structures **/ load_voice(&voices[0],(*stanza).voice1,1); load_voice(&voices[1],(*stanza).voice2,2); load_voice(&voices[2],(*stanza).voice3,3); load_voice(&voices[3],(*stanza).voice4,4); /** how many voices do we have data for? **/ for (i=0; i<4; i++) if (voices[i].time_to_go == -1) break; num_voices = i; /** while we still have some voices to give data to **/ while (num_voices > 0) { /** find voices that are ready for another note **/ for (i=0; i<num_voices; i++) if (voices[i].time_to_go == 0) { note_id = *(voices[i].notes++); octave = *(voices[i].octaves++); duration = *(voices[i].durations++); voice_num = voices[i].voice_num; note(note_id, octave, voice_num, duration); voices[i].time_to_go = duration; } /** find the task with the shortest time and we'll decrement **/ /** the other tasks by its time and wait on it; **/ wait_time = 10000; for (i=0; i<num_voices; i++) if (voices[i].time_to_go < wait_time) { wait_time = voices[i].time_to_go; voice_num = voices[i].voice_num; } /** update the time of all tasks **/ for (i=0; i<num_voices; i++) voices[i].time_to_go -= wait_time; /** wait on the voice that will be done first **/ go_on_voice(voice_num); /** remove voices with no more notes; **/ i = 0; while(i < num_voices) { if (*(voices[i].notes) == -42) { /** delete voice # i **/ for (j=i; j<num_voices-1; j++) voices[j] = voices[j+1]; num_voices--; } else i++; } } } main() { play_stanza(&stanza1); play_stanza(&stanza2); play_stanza(&stanza3); play_stanza(&stanza4); } @//E*O*F music.c// chmod u=rw,g=rw,o=rw music.c echo x - beeper.c sed 's/^@//' > "beeper.c" <<'@//E*O*F beeper.c//' /* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; File: beeper.c ; SCCS: %A% %G% %U% ; Description: Access Gator/Bobcat beeper ; Author: ; Created: 2-Aug-85 ; Modified: 7-Aug-85 17:00:34 ; Language: C ; Package: PSL ; ; (c) Copyright 1985, Hewlett-Packard Company, all rights reserved. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */ /* Public functions: beep noise beep_or_noise_left We offer three voices and a noise source. Each sound is controllable in pitch, volume and duration. Pitch goes from 0 to 1023, volume goes from 0 to 15, duration is between 0 and 255 10msec intervalls. A duration of 0 turns the voice on continuously. A volume of 0 turns it off. The manufacturing specs give details on the programming interface. Here is a summary: The beeper is accessed through ioctl calls. The request argument is either "Send data to beeper" or "Read voice values from beeper". The argument is a pointer to a 4 byte buffer. These four bytes are defined here. R0-R3: Register address field. In the order R2, R1, R0: 0 0 0: Voice 1 frequency 0 0 1: Voice 1 attenuation 0 1 0: Voice 2 frequency 0 1 1: Voice 2 attenuation 1 0 0: Voice 3 frequency 1 0 1: Voice 3 attenuation 1 1 0: Noise control 1 1 1: Noise attentuation F0-F9: 10 bits pitch A0-A3: Attenuation D0-D7: Duration in 10msec's The placement of data in the buffer is a bit srewy: Byte 0 (Frequency 1): 1 R2 R1 R0 F3 F2 F1 F0 LSB Byte 1(Frequency 2): 0 0 F9 F8 F7 F6 F5 F4 Byte 2 (Attenuator) : 1 R2 R1 R0 A3 A2 A1 A0 Byte 3 (Duration) : D7 D6 D5 D4 D3 D2 D1 D0 The volume is inversely proportional to the attenuation. In order to provide rising numbers for rising loudness to the user, we expect a volume and modify to get the attenuation. The same goes for the pitch. In order to calculate frequency of the pitch, use: 83333/(pitch-1023) It is possible at any time to request the time any voice has left to run. This is done by: F4: Read voice1 timer F5: Read voice2 timer F6: Read voice3 timer F7: Read voice4 timer (noise) Noise is generated using a shift register. The following controls are possible for noise: - Attenuation - Duration - Periodic or white noise - 3 shift rates or output of voice 4 as shift rate Bytes 0 and 1 of the data buffer must both have identical contents to control the noise. Attenuation and duration are as in the other voices. Bytes 0 and 1 should look like this: 1 R2 R1 R0 0 FB NF1 NF0 LSB R2, R1 and R0 must be 1, 1 and 0. If FB is 0, periodic noise is generated. If FB is 1, white noise is produced. NF1 and NF2 control the shift rate of the noise generator: NF1 NF2 Shift Rate -------------------------- 0 0 M/64 0 1 M/128 1 0 M/256 1 1 Uses tone generator 3 output M is related to the clock rate. The voice start routines return 0 if all is well, -1 if we had trouble accessing the device file for the beeper and -2 if given parameters were out of range: */ #include <fcntl.h> #include <sys/hilioctl.h> /********************************************************************* *DEFINES: * *********************************************************************/ #define ALL_OK 0 #define ACCESS_PROBLEM -1 #define BAD_RANGE -2 #define BEEPER_DEVICE "/dev/rhil" #define VOICE1_FREQ_REG 0x80 /* Top nibbles for byte0 for all voices: */ #define VOICE2_FREQ_REG 0xA0 #define VOICE3_FREQ_REG 0xC0 #define NOISE_FREQ_REG 0xE0 #define VOICE1_VOL_REG 0x90 /* Top nibbles for byte2 for all voices: */ #define VOICE2_VOL_REG 0xB0 #define VOICE3_VOL_REG 0xD0 #define NOISE_VOL_REG 0xF0 #define MIN_VOICE 1 /* Legal ranges for parms from user: */ #define MAX_VOICE 3 #define MIN_PITCH 0 #define MAX_PITCH 1023 #define MIN_DURATION 0 #define MAX_DURATION 255 #define MIN_VOLUME 0 #define MAX_VOLUME 15 #define MIN_TYPE 0 #define MAX_TYPE 1 #define MIN_RATE 0 #define MAX_RATE 3 static int beeper_fd = -1; /********************************************************************* * PUBLIC FUNCTIONS: * *********************************************************************/ /***************************************************************************** * * * Beep using specified voice: * * * * TAKES: * * * * VOICE : from 1 to 3 * * PITCH : from 0 to 1023 (incl) * * VOLUME : from 0 to 15 (incl). Zero turns voice off. * * DURATION : from 0 to 255 (incl). Zero turns voice on continuously. * * * * RETURNS: * * * * 0 : All ok * * -1 : Cannot access beeper device file * * -2 : Parameter out of range * * * ******************************************************************************/ beep(voice,pitch,volume,duration) int voice,pitch,volume,duration; { unsigned char buffer[4]; /* Check ranges of parameters: */ if ( (voice < MIN_VOICE) || (voice > MAX_VOICE) || (pitch < MIN_PITCH) || (pitch > MAX_PITCH) || (volume < MIN_VOLUME) || (volume > MAX_VOLUME) || (duration < MIN_DURATION) || (duration > MAX_DURATION) ) return(BAD_RANGE); /* Check whether beeper device has already been opened: */ if (beeper_fd < 0) if ((beeper_fd = open(BEEPER_DEVICE,O_RDWR)) < 0) return(ACCESS_PROBLEM); /* Init the voice dependent data bytes. Note the inversion of user's volume and pitch specs to attenuation: */ volume = MAX_VOLUME - volume; pitch = MAX_PITCH - pitch; switch (voice) { case 1: buffer[0] = VOICE1_FREQ_REG | (pitch & 0x0000000f); buffer[2] = VOICE1_VOL_REG | (volume & 0x0000000f); break; case 2: buffer[0] = VOICE2_FREQ_REG | (pitch & 0x0000000f); buffer[2] = VOICE2_VOL_REG | (volume & 0x0000000f); break; case 3: buffer[0] = VOICE3_FREQ_REG | (pitch & 0x0000000f); buffer[2] = VOICE3_VOL_REG | (volume & 0x0000000f); break; }; /* The high 6 bits of the pitch go into byte 1: */ buffer[1] = 0x0000003f & (pitch >> 4); /* Duration: */ buffer[3] = duration; if (ioctl(beeper_fd,EFTSBP,buffer) < 0) return(ACCESS_PROBLEM); return(ALL_OK); } /* end function beep */ /*----------------------------------------------------*/ /****************************************************************************** * Produce noise. * * * * TAKES: * * * * TYPE : from 0 to 1. 0 is periodic noise. 1 is white noise. * * RATE : from 0 to 3. 0 is M/64. 1 is M/128. 2 is M/256. 3 means rate * * determined by output of voice 3. * * VOLUME : from 0 to 15 (incl). Zero turns voice off. * * DURATION : from 0 to 255 (incl). Zero turns voice on continuously. * * * * RETURNS: * * * * 0 : All ok * * -1 : Cannot access beeper device file * * -2 : Parameter out of range * ******************************************************************************/ noise(type,rate,volume,duration) int type,rate,volume,duration; { unsigned char buffer[4]; /* Check ranges of parameters: */ if ( (type < MIN_TYPE) || (type > MAX_TYPE) || (rate < MIN_RATE) || (rate > MAX_RATE) || (volume < MIN_VOLUME) || (volume > MAX_VOLUME) || (duration < MIN_DURATION) || (duration > MAX_DURATION) ) return(BAD_RANGE); /* Check whether beeper device has already been opened: */ if (beeper_fd < 0) if ((beeper_fd = open(BEEPER_DEVICE,O_RDWR)) < 0) return(ACCESS_PROBLEM); /* Invert the volume provided by the user getting the attenuation: */ volume = MAX_VOLUME - volume; type = type << 2; buffer[0] = NOISE_FREQ_REG | (type | rate); /* Byte one must be identical to byte 0: */ buffer[1] = buffer[0]; buffer[2] = NOISE_VOL_REG | (volume & 0x0000000f); buffer[3] = duration; if (ioctl(beeper_fd,EFTSBP,buffer) < 0) return(ACCESS_PROBLEM); return(ALL_OK); } /* end function noise */ /*----------------------------------------------------*/ /**************************************************************************** * * * Read how many 10msec intervalls are left till a voice has * * beeped to the end. This routine is good for noise also. * * * * TAKES: * * * * voice : from 1 to 4 * * * * RETURNS: * * * * 0 : Beeper has finished * * >0 : Number of 10msec intervalls * * -1 : Cannot access beeper device file * * -2 : Parameter out of range * *****************************************************************************/ beep_or_noise_left(voice) int voice; { unsigned char buffer[4]; /* Check for legal parameter range. The '+1' is to include noise generator: */ if ( (voice < MIN_VOICE) || (voice > (MAX_VOICE + 1)) ) return(BAD_RANGE); /* Check whether beeper device has already been opened: */ if (beeper_fd < 0) if ((beeper_fd = open(BEEPER_DEVICE,O_RDWR)) < 0) return(ACCESS_PROBLEM); /* Get the timer values into the buffer bytes: */ if (ioctl(beeper_fd,EFTRT,buffer) < 0) return(ACCESS_PROBLEM); return((int) buffer[voice-1]); } /* end function beep_or_noise_left */ /*---------------------------------------------------*/ @//E*O*F beeper.c// chmod u=rw,g=rw,o=rw beeper.c echo x - mytune.h sed 's/^@//' > "mytune.h" <<'@//E*O*F mytune.h//' int notes0[] = {5,9,0,5,9,7,5,2,11,0,-1,5,9,0,5,9,7,5,2,-42}; int octaves0[] = {2,2,3,3,3,3,3,3,2,3,0,2,2,3,3,3,3,3,3,-42}; int durations0[] = {187,63,125,125,125,125,125,125,125,125,750,187,63,125,125,125,125,125,125,-42}; struct voice_def voice0 = { notes0, octaves0, durations0}; int notes1[] = {0,8,9,0,8,9,0,8,9,0,0,8,9,0,8,9,0,8,9,-42}; int octaves1[] = {1,0,0,1,0,0,1,0,0,1,1,0,0,1,0,0,1,0,0,-42}; int durations1[] = {250,125,125,250,125,125,250,125,125,125,125,125,125,250,125,125,250,125,125,-42}; struct voice_def voice1 = { notes1, octaves1, durations1}; int notes2[] = {5,8,9,5,8,9,5,8,9,5,5,8,9,5,8,9,5,8,9,-42}; int octaves2[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-42}; int durations2[] = {250,125,125,250,125,125,250,125,125,125,125,125,125,250,125,125,250,125,125,-42}; struct voice_def voice2 = { notes2, octaves2, durations2}; struct stanza_def stanza1 = { &voice0, &voice1, &voice2, NULL}; int notes3[] = {0,2,8,2,8,5,-1,-42}; int octaves3[] = {3,3,2,3,2,2,0,-42}; int durations3[] = {750,125,1000,125,125,125,750,-42}; struct voice_def voice3 = { notes3, octaves3, durations3}; int notes4[] = {0,0,8,9,0,1,2,5,5,1,2,5,5,1,2,5,5,1,2,5,5,1,2,-42}; int octaves4[] = {1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,-42}; int durations4[] = {125,125,125,125,250,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,-42}; struct voice_def voice4 = { notes4, octaves4, durations4}; int notes5[] = {5,5,8,9,5,1,2,10,10,1,2,10,10,1,2,10,10,1,2,10,10,1,2,-42}; int octaves5[] = {0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,-42}; int durations5[] = {125,125,125,125,250,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,-42}; struct voice_def voice5 = { notes5, octaves5, durations5}; struct stanza_def stanza2 = { &voice3, &voice4, &voice5, NULL}; int notes6[] = {5,9,0,5,9,7,5,2,11,0,-1,-1,0,7,7,4,0,-1,0,-42}; int octaves6[] = {2,2,3,3,3,3,3,3,2,3,0,0,3,3,3,3,3,0,3,-42}; int durations6[] = {187,63,125,125,125,125,125,125,125,125,500,125,125,250,250,125,125,125,125,-42}; struct voice_def voice6 = { notes6, octaves6, durations6}; int notes7[] = {0,8,9,0,8,9,0,8,9,0,0,3,4,7,7,3,4,7,7,3,4,-42}; int octaves7[] = {1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,-42}; int durations7[] = {250,125,125,250,125,125,250,125,125,125,125,125,125,125,125,125,125,125,125,125,125,-42}; struct voice_def voice7 = { notes7, octaves7, durations7}; int notes8[] = {5,8,9,5,8,9,5,8,9,5,5,3,4,0,0,3,4,0,0,3,4,-42}; int octaves8[] = {0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,-42}; int durations8[] = {250,125,125,250,125,125,250,125,125,125,125,125,125,125,125,125,125,125,125,125,125,-42}; struct voice_def voice8 = { notes8, octaves8, durations8}; struct stanza_def stanza3 = { &voice6, &voice7, &voice8, NULL}; int notes9[] = {5,5,3,5,3,0,10,8,11,11,10,11,10,8,5,0,3,5,-42}; int octaves9[] = {3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,-42}; int durations9[] = {250,250,62,63,62,63,125,125,250,250,62,63,62,63,125,125,125,125,-42}; struct voice_def voice9 = { notes9, octaves9, durations9}; int notes10[] = {5,5,1,2,5,0,0,8,9,0,0,-42}; int octaves10[] = {1,1,1,1,1,1,1,0,0,1,1,-42}; int durations10[] = {125,125,125,125,500,125,125,125,125,500,250,-42}; struct voice_def voice10 = { notes10, octaves10, durations10}; int notes11[] = {10,10,1,2,10,5,5,8,9,5,5,-42}; int octaves11[] = {0,0,1,1,0,0,0,0,0,0,0,-42}; int durations11[] = {125,125,125,125,500,125,125,125,125,500,250,-42}; struct voice_def voice11 = { notes11, octaves11, durations11}; struct stanza_def stanza4 = { &voice9, &voice10, &voice11, NULL}; @//E*O*F mytune.h// chmod u=rw,g=rw,o=rw mytune.h echo Inspecting for damage in transit... temp=/tmp/shar$$; dtemp=/tmp/.shar$$ trap "rm -f $temp $dtemp; exit" 0 1 2 3 15 cat > $temp <<\!!! 14 31 219 Makefile 443 2139 12314 dbsetup.sl 181 488 4079 music.c 317 1361 12102 beeper.c 88 276 3618 mytune.h 1043 4295 32332 total !!! wc Makefile dbsetup.sl music.c beeper.c mytune.h | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp if [ -s $dtemp ] then echo "Ouch [diff of wc output]:" ; cat $dtemp else echo "No problems found." fi exit 0 /* ---------- */ ~
paulc@hpfcrn.HP.COM (Paul Christofanelli) (02/25/88)
Here's yet another program to play the 300 beeper, complete with some truncated examples. It's not quite complete (e.g., it doesn't play the noise generator) and certainly not very elegant, but I think it requires a little less work to get a tune up and playing than the Lisp beeper player. The interesting thing that I found was that it is able to pretty much play real-time by reading the notes directly from an ascii file. Anyway, unpack the shar file, read the READ_ME and try out some of the example music fragments. It's kind of fun to type in sheet music and listen to it, but translating gets a little tedious after a while (which is why I never finished the pieces). Also, as usual, this stuff is completely unsupported. Have fun! Paul Christofanelli ...hpfcla!paulc # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # This archive contains: # READ_ME play.c chop.fant prel3 # fug2 # # Modification/access file times will be preserved. # Error checking via wc(1) will be performed. LANG=""; export LANG echo x - READ_ME sed 's/^@//' >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): <key sig> <quarter notes per minute> <line of music for voice 1> <line of music for voice 2 or blank line> <line of music for voice 3 or blank 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: <pitch>[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 if test "`wc -lwc <READ_ME`" != ' 90 609 3307' then echo ERROR: wc results of READ_ME are `wc -lwc <READ_ME` should be 90 609 3307 fi touch -m 0113172987 READ_ME touch -a 0216135188 READ_ME chmod 640 READ_ME echo x - play.c cat >play.c <<'@EOF' #include <string.h> #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <math.h> #include <time.h> #include <sys/hilioctl.h> #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<lns_act; voice++) new_meas &= !strcmp(tok[voice][linepos[voice]], "|"); for(voice=0; voice<lns_act; voice++) { tok_ptr = tok[voice][linepos[voice]]; if( tok_ptr && strcmp(tok_ptr,"|") && time_left[voice]==0 || new_meas ) { /* np_set(voice, tok[voice][++linepos[voice]]); v_on(voice); */ v_on(voice, tok[voice][++linepos[voice]]); } } delay = 0x7fffffff; for(voice=0; voice<lns_act; voice++) if ((time_left[voice]<delay) && time_left[voice]) delay=time_left[voice]; if (delay != 0x7fffffff) { wait_note(delay); for(voice=0; voice<lns_act; voice++) if(time_left[voice]) time_left[voice] -= delay; } } goto loop; } void v_on (vnum, cnote) int vnum; char *cnote; { char *notestr, *modstr, *octstr, *attenstr; char *noteptr, *modptr, *octptr, *attenptr, *tm_ptr; int bnote, mod, note, tvar; double count; int intcount, voice; if (cnote == NULL) return ; notestr="C D EF G A B R|"; modstr="bn#"; octstr="0123456"; attenstr="0123456789"; noteptr=strchr(notestr, *cnote); if( noteptr!=NULL ) { bnote = noteptr - notestr; if(key) bnote = bnote - (strchr(flat_str, *noteptr) != NULL); else bnote = bnote + (strchr(sharp_str, *noteptr) != NULL); } else bnote = 14; modptr=strpbrk(modstr, cnote); if( modptr!=NULL ) mod = modptr - modstr - 1; else mod = 0; octptr=strpbrk(cnote, octstr); /* NOTE ORDER of params in strpbrk */ if( octptr!=NULL ) { oct[vnum] = *octptr - 0x30; attenptr = octptr+1; } else attenptr = cnote; attenptr = strpbrk(attenptr, attenstr); if(attenptr != NULL) atten[vnum] = *attenptr - 0x30; /* tvar = strlen(cnote)-1; if (tvar > 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 if test "`wc -lwc <play.c`" != ' 226 581 5005' then echo ERROR: wc results of play.c are `wc -lwc <play.c` should be 226 581 5005 fi touch -m 0121085688 play.c touch -a 0216134188 play.c chmod 666 play.c echo x - chop.fant cat >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 if test "`wc -lwc <chop.fant`" != ' 28 501 1406' then echo ERROR: wc results of chop.fant are `wc -lwc <chop.fant` should be 28 501 1406 fi touch -m 0209183887 chop.fant touch -a 0216133888 chop.fant chmod 666 chop.fant echo x - prel3 cat >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 if test "`wc -lwc <prel3`" != ' 27 364 1639' then echo ERROR: wc results of prel3 are `wc -lwc <prel3` should be 27 364 1639 fi touch -m 0113171587 prel3 touch -a 0216133188 prel3 chmod 666 prel3 echo x - fug2 cat >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 if test "`wc -lwc <fug2`" != ' 14 319 1082' then echo ERROR: wc results of fug2 are `wc -lwc <fug2` should be 14 319 1082 fi touch -m 0113181187 fug2 touch -a 0216135088 fug2 chmod 666 fug2 exit 0