<< File: TuneCompareImpl.mesa>> <> <> <<>> DIRECTORY Commander USING [CommandProc, Register], CommandTool USING [ArgumentVector, Failed, Parse], Convert USING [IntFromRope], IO USING [int, PutF, STREAM], Jukebox USING [CloseJukebox, ArchiveCloseTune, Error, FindJukebox, Handle, OpenJukebox, OpenTune, Tune, TuneSize, EnergyRange, RunArray, LengthRange, RunArrayRange, bytesPerChirp, MissingChirp], Rope USING [ ROPE], TuneAccess USING [ReadRunArray, InterpretRunArrayElement, ReadChirpSamples, ByteBlock, ReadTuneHeader, userHeaderLength, ReadAmbientLevel]; TuneCompareImpl: CEDAR PROGRAM IMPORTS Commander, CommandTool, Convert, IO, Jukebox, TuneAccess = BEGIN CompareTunes: Commander.CommandProc = { tune1: Jukebox.Tune _ NIL; jukebox1: Jukebox.Handle _ NIL; weOpened1: BOOLEAN _ FALSE; tune2: Jukebox.Tune _ NIL; jukebox2: Jukebox.Handle _ NIL; weOpened2: BOOLEAN _ FALSE; { ENABLE Jukebox.Error => {msg _ rope; GOTO QuitInError}; argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd ! CommandTool.Failed => {msg _ errorMsg; GOTO QuitInError}]; IF argv.argc # 5 THEN RETURN [$Failure, "Usage: CompareTunes jukebox1 tuneID1 jukebox2 tuneID2\n"]; TRUSTED { jukebox1 _ Jukebox.FindJukebox[argv[1]]; IF jukebox1 = NIL THEN { weOpened1 _ TRUE; jukebox1 _ Jukebox.OpenJukebox[argv[1]]; }; jukebox2 _ Jukebox.FindJukebox[argv[3]]; IF jukebox2 = NIL THEN { weOpened2 _ TRUE; jukebox2 _ Jukebox.OpenJukebox[argv[3]]; }; tune1 _ Jukebox.OpenTune[self: jukebox1, tuneId: Convert.IntFromRope[argv[2]], write: FALSE]; tune2 _ Jukebox.OpenTune[self: jukebox2, tuneId: Convert.IntFromRope[argv[4]], write: FALSE] }; TRUSTED { IF Jukebox.TuneSize[tune1] # Jukebox.TuneSize[tune2] THEN { cmd.out.PutF["Tunes are of different chirp lengths!\n"]; GOTO Quit } }; { header1: TuneAccess.ByteBlock _ TuneAccess.ReadTuneHeader[jukebox1, tune1, TuneAccess.userHeaderLength, NIL]; header2: TuneAccess.ByteBlock _ TuneAccess.ReadTuneHeader[jukebox2, tune2, TuneAccess.userHeaderLength, NIL]; FOR i: INT IN [0..TuneAccess.userHeaderLength) DO IF header1[i] # header2[i] THEN GOTO mismatch REPEAT mismatch => { cmd.out.PutF["User data headers differ at byte %d\n", IO.int[i]]; GOTO failure } ENDLOOP; cmd.out.PutF["User data headers match\n"] EXITS failure => NULL }; { ambientDiscrepancy: BOOLEAN _ FALSE; TRUSTED { FOR chirpNumber: INT IN [0..Jukebox.TuneSize[tune1]) DO ENABLE Jukebox.MissingChirp => LOOP; IF TuneAccess.ReadAmbientLevel[jukebox1, tune1, chirpNumber] # TuneAccess.ReadAmbientLevel[jukebox2, tune2, chirpNumber] THEN IF ambientDiscrepancy THEN cmd.out.PutF[", %d", IO.int[chirpNumber]] ELSE { ambientDiscrepancy _ TRUE; cmd.out.PutF["Ambient levels differ in chirps %d", IO.int[chirpNumber]] } ENDLOOP}; cmd.out.PutF[IF ambientDiscrepancy THEN "\n" ELSE "Ambient levels match throughout\n"] }; TRUSTED { FOR chirpNumber: INT IN [0..Jukebox.TuneSize[tune1]) DO runArray1, runArray2: REF Jukebox.RunArray; timeAccounted, samplesAccounted: Jukebox.LengthRange _ 0; currRunElement: Jukebox.RunArrayRange _ 0; thisLength: Jukebox.LengthRange; skip, silence: BOOLEAN; cmd.out.PutF["Chirp %d", IO.int[chirpNumber]]; runArray1 _ TuneAccess.ReadRunArray[jukebox1, tune1, chirpNumber, NIL ! Jukebox.MissingChirp => { runArray2 _ TuneAccess.ReadRunArray[jukebox2, tune2, chirpNumber, NIL ! Jukebox.MissingChirp => { cmd.out.PutF[" okay (missing)\n"]; LOOP }]; cmd.out.PutF[":\n chirp missing in first tune\n"]; LOOP } ]; runArray2 _ TuneAccess.ReadRunArray[jukebox1, tune1, chirpNumber, NIL ! Jukebox.MissingChirp => { cmd.out.PutF[":\n chirp missing in second tune\n"]; LOOP }]; WHILE timeAccounted cmd.out.PutF[":\n Run arrays differ at element %d\n", IO.int[currRunElement]]; > Jukebox.bytesPerChirp => cmd.out.PutF[":\n FORMAT ERROR: Run arrays do not describe exactly %d samples\n", IO.int[Jukebox.bytesPerChirp]]; = Jukebox.bytesPerChirp => { samples1: TuneAccess.ByteBlock _ TuneAccess.ReadChirpSamples[jukebox1, tune1, chirpNumber, samplesAccounted]; samples2: TuneAccess.ByteBlock _ TuneAccess.ReadChirpSamples[jukebox2, tune2, chirpNumber, samplesAccounted]; FOR i: INT IN [0..samplesAccounted) DO IF samples1[i] # samples2[i] THEN GOTO mismatch REPEAT mismatch => { cmd.out.PutF[":\n Samples differ at element %d\n", IO.int[i]]; GOTO failure } ENDLOOP; cmd.out.PutF[" okay (%d samples and %d run elements)\n", IO.int[samplesAccounted], IO.int[currRunElement]] EXITS failure => NULL } ENDCASE ENDLOOP}; TRUSTED { Jukebox.ArchiveCloseTune[jukebox1, tune1]; Jukebox.ArchiveCloseTune[jukebox2, tune2]; <> IF weOpened1 THEN jukebox1 _ Jukebox.CloseJukebox[jukebox1]; IF weOpened2 THEN jukebox2 _ Jukebox.CloseJukebox[jukebox2] } EXITS Quit => TRUSTED { IF tune1 # NIL THEN Jukebox.ArchiveCloseTune[jukebox1, tune1]; IF tune2 # NIL THEN Jukebox.ArchiveCloseTune[jukebox2, tune2]; IF jukebox1 # NIL AND weOpened1 THEN jukebox1 _ Jukebox.CloseJukebox[jukebox1]; IF jukebox2 # NIL AND weOpened2 THEN jukebox2 _ Jukebox.CloseJukebox[jukebox2] }; QuitInError => TRUSTED { IF tune1 # NIL THEN Jukebox.ArchiveCloseTune[jukebox1, tune1]; IF tune2 # NIL THEN Jukebox.ArchiveCloseTune[jukebox2, tune2]; IF jukebox1 # NIL AND weOpened1 THEN jukebox1 _ Jukebox.CloseJukebox[jukebox1]; IF jukebox2 # NIL AND weOpened2 THEN jukebox2 _ Jukebox.CloseJukebox[jukebox2]; RETURN [$Failure, msg] } }}; Commander.Register[key: "CompareTunes", proc: CompareTunes, doc: "CompareTunes jukebox1 tuneID1 jukebox2 tuneID2"]; END.