예제 #1
0
    public CommandHandlerResult SetAndEvaluateFormula(string formula, int trackNo, int clipNo)
    {
        var clipRef = new ClipReference(trackNo, clipNo);

        if (ClipSet[clipRef] != ClipSlot.Empty && ClipSet[clipRef].Name == formula)
        {
            return CommandHandlerResult.AbortedResult with {
                       Warnings = new List <string> {
                           $"Aborted evaluation of formula at {clipRef.ToString()} since it was unchanged."
                       }
            }
        }
        ;
        var(success, result, errorMessage) = Parser.ParseFormula(formula);
        if (!success)
        {
            return CommandHandlerResult.AbortedResult with {
                       Errors = new List <string> {
                           errorMessage
                       }
            }
        }
        ;

        var clipSlot = new ClipSlot(formula, new Clip(clipRef), result);

        ClipSet[clipSlot.ClipReference] = clipSlot;
        var(successfulClipRefs, errors) = ClipSet.ProcessClips(new [] { clipSlot });
        return(CommandHandlerResult.CompletedResult with {
            SuccessfulClips = ClipSet.GetClipsFromClipReferences(successfulClipRefs).ToList(), Errors = errors
        });
    }
예제 #2
0
    public void SetFormula(int trackNo, int clipNo, string formula)
    {
        var parsedFormula = Parser.ParseFormula(formula);

        if (parsedFormula.Success)
        {
            var clipRef  = new ClipReference(trackNo, clipNo);
            var clipSlot = new ClipSlot(formula, new Clip(clipRef), parsedFormula.Result);
            ClipSet[clipSlot.ClipReference] = clipSlot;
        }
    }
예제 #3
0
 public void TestDecimalToSpreadshimal()
 {
     Assert.AreEqual("", ClipReference.ToSpreadshimal(0));
     Assert.AreEqual("A", ClipReference.ToSpreadshimal(1));
     Assert.AreEqual("B", ClipReference.ToSpreadshimal(2));
     Assert.AreEqual("Z", ClipReference.ToSpreadshimal(26));
     Assert.AreEqual("AA", ClipReference.ToSpreadshimal(27));
     Assert.AreEqual("AC", ClipReference.ToSpreadshimal(29));
     Assert.AreEqual("ZZ", ClipReference.ToSpreadshimal(702));
     Assert.AreEqual("AAA", ClipReference.ToSpreadshimal(703));
     Assert.AreEqual("AAB", ClipReference.ToSpreadshimal(704));
 }
예제 #4
0
    public static ProcessResult <Formula> ParseFormula(string formula)
    {
        var lexer = new Lexer(formula);

        var(success, tokens, errorMessage) = lexer.GetTokens();
        if (!success)
        {
            return(new ProcessResult <Formula>(errorMessage));
        }

        (success, errorMessage) = AreTokensValid(tokens);
        if (!success)
        {
            return(new ProcessResult <Formula>($"Parsing of formula ${formula} was aborted: {errorMessage}"));
        }
        TreeToken syntaxTree;

        (success, syntaxTree, errorMessage) = CreateSyntaxTree(tokens);
        if (!success)
        {
            return(new ProcessResult <Formula>(errorMessage));
        }

        // remaining steps:
        // convert any nested statements to inline clips - might involve some refactoring where parsing to commands and applying these can be done selectively and not as part of the fixed pipeline we have now

        Token[] commandTokens;
        (success, commandTokens, errorMessage) = ResolveAndFlattenSyntaxTree(syntaxTree);
        if (!success)
        {
            return(new ProcessResult <Formula>(errorMessage));
        }

        try
        {
            var allReferencedClips = commandTokens.Where(x => x.IsClipReference)
                                     .Select(x => ClipReference.FromString(x.Value)).ToList();

            var sourceClipReferences = commandTokens.TakeWhile(x => x.IsClipReference).Select(x => ClipReference.FromString(x.Value)).ToList();
            var commandTokensLists   = ExtractCommandTokensLists(commandTokens.Skip(sourceClipReferences.Count).ToArray());
            var commands             = commandTokensLists.Select(ParseTokensToCommand).ToList();

            var parsedFormula = new Formula(commands, sourceClipReferences, allReferencedClips, new Dictionary <ClipReference, ClipSlot>());
            return(new ProcessResult <Formula>(parsedFormula));
        }
        catch (ArgumentException ae)
        {
            return(new ProcessResult <Formula>($"ParseFormula threw exception: {ae.Message}"));
        }
    }
예제 #5
0
 public void TestSpreadshimalToDecimal()
 {
     Assert.AreEqual(0, ClipReference.FromSpreadshimal(""));
     Assert.AreEqual(1, ClipReference.FromSpreadshimal("A"));
     Assert.AreEqual(2, ClipReference.FromSpreadshimal("B"));
     Assert.AreEqual(26, ClipReference.FromSpreadshimal("Z"));
     Assert.AreEqual(27, ClipReference.FromSpreadshimal("AA"));
     Assert.AreEqual(29, ClipReference.FromSpreadshimal("AC"));
     Assert.AreEqual(702, ClipReference.FromSpreadshimal("ZZ"));
     Assert.AreEqual(703, ClipReference.FromSpreadshimal("AAA"));
     Assert.AreEqual(704, ClipReference.FromSpreadshimal("AAB"));
     Assert.AreEqual(702, ClipReference.FromSpreadshimal("zz"));
     Assert.AreEqual(703, ClipReference.FromSpreadshimal("aaa"));
     Assert.AreEqual(704, ClipReference.FromSpreadshimal("aab"));
 }
예제 #6
0
    public void TestEvaluationOfClipIsAbortedWhenContentsUnchanged()
    {
        var commandHandler = new CommandHandler();
        var result         = commandHandler.SetAndEvaluateClipData(new Clip(4, true)
        {
            ClipReference = ClipReference.FromString("A1"),
            Notes         = new SortedList <NoteEvent> {
                new NoteEvent(36, 0, .5m, 100),
                new NoteEvent(38, 1, .5m, 100),
                new NoteEvent(40, 2, .75m, 100)
            }
        });

        Assert.IsTrue(result.RanToCompletion);

        result = commandHandler.SetAndEvaluateClipData(new Clip(4, true)
        {
            ClipReference = ClipReference.FromString("A1"),
            Notes         = new SortedList <NoteEvent> {
                new NoteEvent(36, 0, .75m, 100),
                new NoteEvent(38, 1, .5m, 100),
                new NoteEvent(40, 2, .5m, 100)
            }
        });
        Assert.IsTrue(result.RanToCompletion);

        result = commandHandler.SetAndEvaluateClipData(new Clip(4, true)
        {
            ClipReference = ClipReference.FromString("A1"),
            Notes         = new SortedList <NoteEvent> {
                new NoteEvent(36, 0, .75m, 100),
                new NoteEvent(38, 1, .5m, 100),
                new NoteEvent(40, 2, .5m, 100)
            }
        });
        Assert.IsFalse(result.RanToCompletion);
        Assert.AreEqual($"Aborted evaluation of clip at A1 since it was unchanged.", result.Warnings.FirstOrDefault());
    }
예제 #7
0
        public static (List <Clip> Clips, string Formula, ushort Id, byte TrackNo) DecodeData(byte[] data)
        {
            var    clips      = new List <Clip>();
            ushort id         = BitConverter.ToUInt16(data, 0);
            byte   trackNo    = data[2];
            byte   numClips   = data[3];
            int    dataOffset = 4;

            // Decode clipdata
            while (clips.Count < numClips)
            {
                ClipReference clipReference = new ClipReference(data[dataOffset], data[dataOffset += 1]);
                decimal       length        = (decimal)BitConverter.ToSingle(data, dataOffset += 1);
                bool          isLooping     = data[dataOffset += 4] == 1;
                var           clip          = new Clip(length, isLooping)
                {
                    ClipReference = clipReference
                };
                ushort numNotes = BitConverter.ToUInt16(data, dataOffset += 1);
                dataOffset += 2;
                for (var i = 0; i < numNotes; i++)
                {
                    clip.Notes.Add(new NoteEvent(
                                       data[dataOffset],
                                       (decimal)BitConverter.ToSingle(data, dataOffset += 1),
                                       (decimal)BitConverter.ToSingle(data, dataOffset += 4),
                                       data[dataOffset += 4])
                                   );
                    dataOffset++;
                }
                clips.Add(clip);
            }
            // Convert remaining bytes to text containing the formula
            string formula = Encoding.ASCII.GetString(data, dataOffset, data.Length - dataOffset);

            return(clips, formula, id, trackNo);
        }
예제 #8
0
 public ClipSlot this[ClipReference clipRef] => ClipSlots[clipRef] ?? ClipSlot.Empty;