[comp.sys.hp] Music

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