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] = { 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] ~ { 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] = { 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 { 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 "]; END. π 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 This information is derived from the data sheet on the Intel 2910A (mu-Law). Binary search assuming decodeArray is valid, but not using encodeArray. r is assumed to be in the range [-1.0 .. 1.0]. Encodes for s in the range [-1.0 .. 1.0], clipping if s is not in that range. This actually returns Sin[s*twoPi] Κe•NewlineDelimiter –(cedarcode) style™codešœ™Kšœ Οeœ1™