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;
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.