BeepsImpl.Mesa
Copyright Ó 1992 by Xerox Corporation. All rights reserved.
Last tweaked by Mike Spreitzer on November 6, 1989 4:25:45 pm PST
Chauser, July 15, 1991 10:32 am PDT
DIRECTORY Basics, Beeps, Commander, IO, Real, RealFns, Rope, UXIO;
BeepsImpl: CEDAR PROGRAM
IMPORTS Commander, IO, Real, RealFns, UXIO
EXPORTS Beeps
=
BEGIN OPEN Beeps;
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
MuLawByte: TYPE = MACHINE DEPENDENT RECORD [
SELECT OVERLAID * FROM
byte => [byte: BYTE],
coded => [positive: BOOL, code: [0..128)],
parts => [pos: BIT, octant: [0..7], rem: [0..15]]
ENDCASE
];
Scaled: TYPE = Basics.LongNumber;
K: CARD = 64*1024;
L: CARD = 8*1024;
M: CARD = 8159;
can: PUBLIC BOOL ¬ TRUE;
Cant: PUBLIC ERROR ~ CODE;
pi: REAL ¬ 3.14159;
decodeArray: REF DecodeArray ¬ InitDecodeArray[];
DecodeArray: TYPE = ARRAY BYTE OF Scaled;
encodeArray: REF EncodeArray ¬ InitEncodeArray[];
EncodeArray: TYPE = PACKED ARRAY EncodeArrayIndex OF BYTE;
EncodeArrayIndex: TYPE = [0..M];
sinScaled: REF ScaledArray ¬ InitSinScaled[];
ScaledArray: TYPE = ARRAY ScaledArrayIndex OF Scaled;
ScaledArrayIndex: TYPE = [0..L);
InitDecodeArray: PROC RETURNS [REF DecodeArray] = {
This information is derived from the data sheet on the Intel 2910A (mu-Law).
array: REF DecodeArray ¬ NEW[DecodeArray];
FOR b: BYTE IN BYTE DO
m: MuLawByte = [byte[b]];
i: INT ¬ 0;
rem: BYTE = m.rem;
SELECT m.octant FROM
0 => i ¬ 8159-256*rem;
1 => i ¬ 4063-128*rem;
2 => i ¬ 2015-64*rem;
3 => i ¬ 991-32*rem;
4 => i ¬ 479-16*rem;
5 => i ¬ 223-8*rem;
6 => i ¬ 95-4*rem;
7 => IF rem # 15 THEN i ¬ 31-2*rem;
ENDCASE;
IF NOT m.positive THEN i ¬ -i;
i ¬ i * (K/L);
array[b] ¬ [int[i]];
ENDLOOP;
RETURN [array];
};
InitEncodeArray: PROC RETURNS [REF EncodeArray] = {
array: REF EncodeArray ¬ NEW[EncodeArray];
adj: REAL ¬ 1.0/L;
FOR i: EncodeArrayIndex IN EncodeArrayIndex DO
array[i] ¬ HeavyEncode[REAL[i]*adj];
ENDLOOP;
RETURN [array];
};
HeavyEncode: PROC [r: REAL] RETURNS [BYTE] ~ {
Binary search assuming decodeArray is valid, but not using encodeArray. r is assumed to be in the range [-1.0 .. 1.0].
hiIndex: BYTE ¬ 255;
loIndex: BYTE ¬ 0;
increasing: BOOL ¬ TRUE;
r ¬ r * K;
IF r <= 0 THEN hiIndex ¬ 127 ELSE loIndex ¬ 128;
IF decodeArray[hiIndex].int < decodeArray[loIndex].int THEN increasing ¬ FALSE;
DO
IF (hiIndex-loIndex) > 1
THEN {
midIndex: BYTE = (hiIndex+loIndex)/2;
midValue: REAL = REAL[decodeArray[midIndex].int];
IF increasing
THEN
IF r >= midValue THEN loIndex ¬ midIndex ELSE hiIndex ¬ midIndex
ELSE
IF r <= midValue THEN loIndex ¬ midIndex ELSE hiIndex ¬ midIndex;
}
ELSE {
hiValue: REAL = REAL[decodeArray[hiIndex].int];
loValue: REAL = REAL[decodeArray[loIndex].int];
IF ABS[hiValue-r] < ABS[loValue-r] THEN RETURN [hiIndex] ELSE RETURN [loIndex];
};
ENDLOOP;
};
EncodeScaled: PROC [s: Scaled] RETURNS [BYTE] = {
Encodes for s in the range [-1.0 .. 1.0], clipping if s is not in that range.
top: BYTE ¬ 0;
index: EncodeArrayIndex ¬ EncodeArrayIndex.LAST;
IF s.int < 0 THEN {s.int ¬ -s.int; top ¬ 128};
s.card ¬ s.card / (K/L);
IF s.card < index THEN index ¬ LOOPHOLE[s.card];
RETURN [encodeArray[index]-top];
};
RealToScaled: PROC [r: REAL] RETURNS [Scaled] = {
RETURN [[int[Real.Floor[r*K+0.5]]]];
};
InitSinScaled: PROC [debug: STREAM ¬ NIL] RETURNS [REF ScaledArray] = {
table: REF ScaledArray ¬ NEW[ScaledArray];
cvt: REAL ¬ 2.0*pi/L;
FOR i: ScaledArrayIndex IN ScaledArrayIndex DO
r: REAL = i*cvt;
sin: REAL = RealFns.Sin[r];
s: Scaled ¬ RealToScaled[sin];
table[i] ¬ s;
IF table[i] # s THEN ERROR;
IF debug # NIL AND s.int = 0 THEN {
IO.PutF[debug, "In InitSinScaled, i = %g, i*cvt = %g, sin = %g\n",
[integer[i]], [real[r]], [real[sin]] ];
};
ENDLOOP;
RETURN [table];
};
SinScaled: PROC [s: Scaled] RETURNS [Scaled] = INLINE {
This actually returns Sin[s*twoPi]
RETURN [sinScaled[(s.card / (K/L)) MOD L]];
};
Beep: PUBLIC PROC [frequency, duration: CARDINAL] ~ {
{ ENABLE UXIO.Error => CONTINUE;
st: STREAM ~ UXIO.CreateFileStream["/dev/audio", write];
phaseStep: Scaled ~ RealToScaled[frequency/REAL[L]];
rem: INT ¬ Real.Floor[duration*0.001*L];
accum: Scaled ¬ [int[0]];
pos: NAT ¬ 0;
data: PACKED ARRAY DataIndex OF BYTE;
DataIndex: TYPE = [0..1024);
WHILE rem > 0 DO
sin: Scaled = SinScaled[accum];
data[pos] ¬ EncodeScaled[sin];
pos ¬ pos + 1;
IF pos > DataIndex.LAST THEN TRUSTED {
IO.UnsafePutBlock[st, [LOOPHOLE[@data], 0, pos]];
pos ¬ 0;
};
accum.int ¬ accum.int + phaseStep.int;
rem ¬ rem - 1;
ENDLOOP;
IF pos > 0 THEN TRUSTED {
IO.UnsafePutBlock[st, [LOOPHOLE[@data], 0, pos]];
};
IO.Flush[st];
IO.Close[st];
RETURN};
};
BeepCmd: Commander.CommandProc ~ {
cl: STREAM ~ IO.RIS[cmd.commandLine];
freq: CARDINAL ~ cl.GetInt[];
dur: CARDINAL ~ cl.GetInt[];
Beep[freq, dur];
RETURN};
Commander.Register["Beep", BeepCmd, "Beep <freq> <ms>"];
END.