From e45f7aff85fc65db9f5a6fdcc5081e67d5c73447 Mon Sep 17 00:00:00 2001 From: Takeshi Yokemura Date: Sat, 7 Aug 2021 19:35:43 +0900 Subject: [PATCH 1/9] Parser fix --- Source/FrameSequenceParser.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Source/FrameSequenceParser.cpp b/Source/FrameSequenceParser.cpp index ff3696c..34e003e 100644 --- a/Source/FrameSequenceParser.cpp +++ b/Source/FrameSequenceParser.cpp @@ -373,11 +373,10 @@ FrameSequence FrameSequenceParser::parse (const String& input, { if (hasRelease) { - str_beforeRepeat = trimmed.substring (0, repeatStartIndex - 1); + str_release = trimmed.substring(releaseBlockIndex, trimmed.length()); } - - str_insideRepeat = trimmed.substring (repeatStartIndex, repeatEndIndex); - } + str_beforeRepeat = trimmed.substring(0, repeatStartIndex - 1); + str_insideRepeat = trimmed.substring (repeatStartIndex, repeatEndIndex); } else { if (hasRelease) From ad947fcfda9b7b42425ad58c61d489570d1f644c Mon Sep 17 00:00:00 2001 From: Takeshi Yokemura Date: Fri, 13 Aug 2021 18:09:27 +0900 Subject: [PATCH 2/9] Open methods for testing --- Source/FrameSequenceParser.cpp | 125 +++++++++++++++++++++++++++++++-- Source/FrameSequenceParser.h | 29 ++++++++ 2 files changed, 147 insertions(+), 7 deletions(-) diff --git a/Source/FrameSequenceParser.cpp b/Source/FrameSequenceParser.cpp index 34e003e..e7c855e 100644 --- a/Source/FrameSequenceParser.cpp +++ b/Source/FrameSequenceParser.cpp @@ -10,11 +10,7 @@ #include "FrameSequenceParser.h" -// -// Fileprivate -// - -std::vector parseSlope (const String& input, +std::vector FrameSequenceParser::parseSlope (const String& input, int minValue, int maxValue, ParseError* error) @@ -115,7 +111,7 @@ std::vector parseSlope (const String& input, return retval; } -std::vector parseRepeat (const String& input, +std::vector FrameSequenceParser::parseRepeat (const String& input, int minValue, int maxValue, ParseError* error) @@ -172,7 +168,7 @@ std::vector parseRepeat (const String& input, return retval; } -std::vector parseSegment (const String& input, +std::vector FrameSequenceParser::parseSegment (const String& input, int minValue, int maxValue, ParseError* error) @@ -228,6 +224,121 @@ std::vector parseSegment (const String& input, return retval; } +FrameSequenceParser::SegmentIndexes FrameSequenceParser::findSegment(const String& input) { + int releaseBlockIndex = -1; + int repeatStartIndex = -1; + int repeatEndIndex = -1; + int openBracketCount = 0; + int closeBracketCount = 0; + + SegmentIndexes retval = SegmentIndexes(); + + // loop by character + for (int i = 0; i < input.length(); i++) + { + if (input[i] == '|') // found "|": + { + if (releaseBlockIndex >= 0) + { + // if releaseBlockIndex is already determined: Duplication Error + retval.error = kParseErrorDuplicatedReleaseDelimiter; + return retval; + } + + // if(repeatStartIndex >= 0) { + // // if appeard before "[" or "]": Repetition After Release Error + // throw new FrameSequenceParseException(TRANS("You cannot repeat in release phase"), true); + // } + // set releaseBlockIndex + releaseBlockIndex = i + 1; + + if (repeatEndIndex < 0) + { + // if "]" is omitted: Also set repeatEndIndex + repeatEndIndex = i; + } + } + + if (input[i] == '[') /// found "[": + { + openBracketCount++; + + if (openBracketCount > 1) + { + // Duplication Error + retval.error = kParseErrorDuplicatedOpenBracket; + return retval; + } + + if (releaseBlockIndex >= 0) + { + // if repeat end is already defined: Repetition After Release Error + retval.error = kParseErrorRepeatingInReleaseBlock; + return retval; + } + + if (repeatEndIndex >= 0) + { + // if repeat end is already defined: Repetition After Release Error + retval.error = kParseErrorDuplicatedOpenBracket; + return retval; + } + + // set repeatStartIndex + repeatStartIndex = i + 1; + } + + if (input[i] == ']') // found "]": + { + closeBracketCount++; + + if (closeBracketCount > 1) + { + // Duplication Error + retval.error = kParseErrorDuplicatedCloseBracket; + return retval; + } + + if (repeatStartIndex < 0) + { + // if repeatStartIndex hasn't set: Syntax Error + retval.error = kParseErrorUnmatchingCloseBracket; + return retval; + } + + if (releaseBlockIndex >= 0) + { + // if repeat end is already defined: Repetition After Release Error + retval.error = kParseErrorRepeatingInReleaseBlock; + return retval; + } + + repeatEndIndex = i; + } + } + + // if (releaseBlockIndex < 0) { // "|" didn't explicitly specified + // releaseBlockIndex = trimmed.length(); + // } + + if (openBracketCount != closeBracketCount) + { + retval.error = kParseErrorUnmatchingBracketNumber; + return retval; + } + + if (releaseBlockIndex - repeatEndIndex > 1) + { + // throw new FrameSequenceParseException(TRANS("Elements between repeat block and release block will be ignored"), false); + // FiXME: non-fatal exceptionをどう扱うか + } + + retval.releaseBlockIndex = releaseBlockIndex; + retval.repeatStartIndex = repeatStartIndex; + retval.repeatEndIndex = repeatEndIndex; + return retval; +} + FrameSequence FrameSequenceParser::parse (const String& input, int minValue, int maxValue, diff --git a/Source/FrameSequenceParser.h b/Source/FrameSequenceParser.h index 67c8cc0..15ca5d5 100644 --- a/Source/FrameSequenceParser.h +++ b/Source/FrameSequenceParser.h @@ -15,5 +15,34 @@ struct FrameSequenceParser { + /* + Public + */ FrameSequence parse (const String& input, int minValue, int maxValue, ParseError* error); + + /* + Semantically private (leave them open for unit testing) + */ + struct SegmentIndexes { + const int NONE = -1; + + int releaseBlockIndex = NONE; + int repeatStartIndex = NONE; + int repeatEndIndex = NONE; + ParseError error; + }; + + std::vector parseSlope (const String& input, + int minValue, + int maxValue, + ParseError* error); + std::vector parseRepeat (const String& input, + int minValue, + int maxValue, + ParseError* error); + std::vector parseSegment (const String& input, + int minValue, + int maxValue, + ParseError* error); + SegmentIndexes findSegment(const String& input); }; From 846133ac39e2df5bc7169718061b47ff5669f9cc Mon Sep 17 00:00:00 2001 From: Takeshi Yokemura Date: Sun, 15 Aug 2021 10:31:23 +0900 Subject: [PATCH 3/9] (1)Added test class (2)Use separated findSegment method --- Magical8bitPlug2.jucer | 4 ++ Source/EnvelopeParserTest.h | 90 ++++++++++++++++++++++++++ Source/FrameSequenceParser.cpp | 111 ++------------------------------- Source/FrameSequenceParser.h | 18 +++--- Source/PluginProcessor.cpp | 9 ++- 5 files changed, 116 insertions(+), 116 deletions(-) create mode 100644 Source/EnvelopeParserTest.h diff --git a/Magical8bitPlug2.jucer b/Magical8bitPlug2.jucer index a4db363..a8b4e52 100644 --- a/Magical8bitPlug2.jucer +++ b/Magical8bitPlug2.jucer @@ -10,6 +10,10 @@ pluginDesc="8bit sound generator 2nd ver. by YMCK" displaySplashScreen="1" jucerFormatVersion="1" version="1.0.1"> + + + FrameSequenceParser::parseSegment (const String& input, return retval; } -FrameSequenceParser::SegmentIndexes FrameSequenceParser::findSegment(const String& input) { +SegmentIndexes FrameSequenceParser::findSegment(const String& input) { int releaseBlockIndex = -1; int repeatStartIndex = -1; int repeatEndIndex = -1; @@ -359,112 +359,11 @@ FrameSequence FrameSequenceParser::parse (const String& input, // // Overall structure // + SegmentIndexes si = findSegment(trimmed); - int releaseBlockIndex = -1; - int repeatStartIndex = -1; - int repeatEndIndex = -1; - int openBracketCount = 0; - int closeBracketCount = 0; - - // loop by character - for (int i = 0; i < trimmed.length(); i++) - { - if (trimmed[i] == '|') // found "|": - { - if (releaseBlockIndex >= 0) - { - // if releaseBlockIndex is already determined: Duplication Error - *error = kParseErrorDuplicatedReleaseDelimiter; - return fs; - } - - // if(repeatStartIndex >= 0) { - // // if appeard before "[" or "]": Repetition After Release Error - // throw new FrameSequenceParseException(TRANS("You cannot repeat in release phase"), true); - // } - // set releaseBlockIndex - releaseBlockIndex = i + 1; - - if (repeatEndIndex < 0) - { - // if "]" is omitted: Also set repeatEndIndex - repeatEndIndex = i; - } - } - - if (trimmed[i] == '[') /// found "[": - { - openBracketCount++; - - if (openBracketCount > 1) - { - // Duplication Error - *error = kParseErrorDuplicatedOpenBracket; - return fs; - } - - if (releaseBlockIndex >= 0) - { - // if repeat end is already defined: Repetition After Release Error - *error = kParseErrorRepeatingInReleaseBlock; - return fs; - } - - if (repeatEndIndex >= 0) - { - // if repeat end is already defined: Repetition After Release Error - *error = kParseErrorDuplicatedOpenBracket; - return fs; - } - - // set repeatStartIndex - repeatStartIndex = i + 1; - } - - if (trimmed[i] == ']') // found "]": - { - closeBracketCount++; - - if (closeBracketCount > 1) - { - // Duplication Error - *error = kParseErrorDuplicatedCloseBracket; - return fs; - } - - if (repeatStartIndex < 0) - { - // if repeatStartIndex hasn't set: Syntax Error - *error = kParseErrorUnmatchingCloseBracket; - return fs; - } - - if (releaseBlockIndex >= 0) - { - // if repeat end is already defined: Repetition After Release Error - *error = kParseErrorRepeatingInReleaseBlock; - return fs; - } - - repeatEndIndex = i; - } - } - - // if (releaseBlockIndex < 0) { // "|" didn't explicitly specified - // releaseBlockIndex = trimmed.length(); - // } - - if (openBracketCount != closeBracketCount) - { - *error = kParseErrorUnmatchingBracketNumber; - return fs; - } - - if (releaseBlockIndex - repeatEndIndex > 1) - { - // throw new FrameSequenceParseException(TRANS("Elements between repeat block and release block will be ignored"), false); - // FiXME: non-fatal exceptionをどう扱うか - } + int releaseBlockIndex = si.releaseBlockIndex; + int repeatStartIndex = si.repeatStartIndex; + int repeatEndIndex = si.repeatEndIndex; // Just for convenience bool hasRelease = (releaseBlockIndex >= 0); diff --git a/Source/FrameSequenceParser.h b/Source/FrameSequenceParser.h index 15ca5d5..dccc77a 100644 --- a/Source/FrameSequenceParser.h +++ b/Source/FrameSequenceParser.h @@ -13,6 +13,15 @@ #include "FrameSequence.h" #include "FrameSequenceParseErrors.h" +struct SegmentIndexes { + static const int NONE = -1; + + int releaseBlockIndex = NONE; + int repeatStartIndex = NONE; + int repeatEndIndex = NONE; + ParseError error; +}; + struct FrameSequenceParser { /* @@ -23,15 +32,6 @@ struct FrameSequenceParser /* Semantically private (leave them open for unit testing) */ - struct SegmentIndexes { - const int NONE = -1; - - int releaseBlockIndex = NONE; - int repeatStartIndex = NONE; - int repeatEndIndex = NONE; - ParseError error; - }; - std::vector parseSlope (const String& input, int minValue, int maxValue, diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 270ea3b..27b41f7 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -14,6 +14,7 @@ #include "TriangleVoice.h" #include "NoiseVoice.h" #include "FrameSequenceParseErrors.h" +#include "EnvelopeParserTest.h" //============================================================================== Magical8bitPlug2AudioProcessor::Magical8bitPlug2AudioProcessor() @@ -114,7 +115,7 @@ Magical8bitPlug2AudioProcessor::Magical8bitPlug2AudioProcessor() std::make_unique ("isPitchSequenceEnabled_raw", "Enabled", false), std::make_unique ("isDutySequenceEnabled_raw", "Enabled", false), std::make_unique ("pitchSequenceMode_raw", "Mode", StringArray ({"Coarse", "Fine"}), 0) -} + } ) , settingRefs (¶meters) #ifndef JucePlugin_PreferredChannelConfigurations @@ -132,6 +133,12 @@ Magical8bitPlug2AudioProcessor::Magical8bitPlug2AudioProcessor() setupVoice(); synth.addSound (new GenericSound()); + +#if JUCE_DEBUG + EnvelopeParserTest test; + UnitTestRunner runner; + runner.runAllTests(); +#endif } Magical8bitPlug2AudioProcessor::~Magical8bitPlug2AudioProcessor() From 252a84d618d191ebe74216d59b6067f233abee2c Mon Sep 17 00:00:00 2001 From: Takeshi Yokemura Date: Sun, 15 Aug 2021 15:17:48 +0900 Subject: [PATCH 4/9] Slope parser test --- Source/EnvelopeParserTest.h | 104 +++++++++++++++++++++++++++++- Source/FrameSequenceParseErrors.h | 1 + Source/FrameSequenceParser.cpp | 17 +++-- 3 files changed, 115 insertions(+), 7 deletions(-) diff --git a/Source/EnvelopeParserTest.h b/Source/EnvelopeParserTest.h index 4e5e443..d9f8043 100644 --- a/Source/EnvelopeParserTest.h +++ b/Source/EnvelopeParserTest.h @@ -22,7 +22,12 @@ public: void runTest() override { FrameSequenceParser parser; - + + //------------------------------------------------------- + // + // Section index + // + //------------------------------------------------------- beginTest ("No repeat"); String input1 = "aaa"; // At this phase it doesn't matter if it contains numbers or not auto result1 = parser.findSegment(input1); @@ -86,5 +91,102 @@ public: expect(result9.repeatEndIndex == 7); expect(result9.releaseBlockIndex == 9); + beginTest ("[Error] Multiple open bracket"); + String input10 = "aaa[[bbb]"; + auto result10 = parser.findSegment(input10); + expect(result10.error = kParseErrorDuplicatedOpenBracket); + + beginTest ("[Error] Multiple close bracket"); + String input11 = "aaa[bbb]]"; + auto result11 = parser.findSegment(input11); + expect(result11.error = kParseErrorDuplicatedCloseBracket); + + beginTest ("[Error] Unmatching close bracket"); + String input12 = "aaabbb]"; + auto result12 = parser.findSegment(input12); + expect(result12.error = kParseErrorUnmatchingCloseBracket); + + beginTest ("[Error] Repeat in release segment"); + String input13 = "aaa|[bbb]"; + auto result13 = parser.findSegment(input13); + expect(result13.error = kParseErrorRepeatingInReleaseBlock); + + //------------------------------------------------------- + // + // Slope + // + //------------------------------------------------------- + ParseError error = kParseErrorNone; + + beginTest ("Down slope"); + String input14 = "3to0in4"; + std::vector result14 = parser.parseSlope(input14, 0, 15, &error); + expect(result14[0] == 3); + expect(result14[1] == 2); + expect(result14[2] == 1); + expect(result14[3] == 0); // Should include the last value + + beginTest ("Slow decrement"); + String input15 = "2to0in8"; + std::vector result15 = parser.parseSlope(input15, 0, 15, &error); + expect(result15[0] == 2); + expect(result15[1] == 2); + expect(result15[2] == 1); + expect(result15[3] == 1); + expect(result15[4] == 1); + expect(result15[5] == 1); + expect(result15[6] == 0); + expect(result15[7] == 0); + + beginTest ("Fast decrement"); + String input16 = "15to0in5"; + std::vector result16 = parser.parseSlope(input16, 0, 15, &error); + expect(result16[0] == 15); + expect(result16[1] == 11); + expect(result16[2] == 8); + expect(result16[3] == 4); + expect(result16[4] == 0); + + beginTest ("Up slope"); + String input17 = "0to3in4"; + std::vector result17 = parser.parseSlope(input17, 0, 15, &error); + expect(result17[0] == 0); + expect(result17[1] == 1); + expect(result17[2] == 2); + expect(result17[3] == 3); // Should include the last value + + beginTest ("[Error] Missing 'in'"); + String input18 = "0to3"; + std::vector result18 = parser.parseSlope(input18, 0, 15, &error); + expect(error == kParseErrorMissingSlopeLengthDelimiter); + + beginTest ("[Error] Missing initial value"); + String input19 = "to5in5"; + std::vector result19 = parser.parseSlope(input19, 0, 15, &error); + expect(error == kParseErrorMissingSlopeInitialValue); + + beginTest ("[Error] Missing final value"); + String input20 = "4toin5"; + std::vector result20 = parser.parseSlope(input20, 0, 15, &error); + expect(error == kParseErrorMissingSlopeFinalValue); + + beginTest ("[Error] Missing frame count"); + String input21 = "0to3in"; + std::vector result21 = parser.parseSlope(input21, 0, 15, &error); + expect(error == kParseErrorMissingSlopeFrameCount); + + + //------------------------------------------------------- + // + // Repeat + // + //------------------------------------------------------- + + //------------------------------------------------------- + // + // Total + // + //------------------------------------------------------- + } }; diff --git a/Source/FrameSequenceParseErrors.h b/Source/FrameSequenceParseErrors.h index 68881bc..a65a076 100644 --- a/Source/FrameSequenceParseErrors.h +++ b/Source/FrameSequenceParseErrors.h @@ -27,6 +27,7 @@ enum ParseError kParseErrorMissingSlopeLengthDelimiter, kParseErrorMissingSlopeInitialValue, kParseErrorMissingSlopeFinalValue, + kParseErrorMissingSlopeFrameCount, kParseErrorNotANumber, kParseErrorValueOutOfRange, kParseErrorFrameLengthTooShort, diff --git a/Source/FrameSequenceParser.cpp b/Source/FrameSequenceParser.cpp index 713d440..c3807a5 100644 --- a/Source/FrameSequenceParser.cpp +++ b/Source/FrameSequenceParser.cpp @@ -36,18 +36,23 @@ std::vector FrameSequenceParser::parseSlope (const String& input, // find index of "in" int inIndex = input.indexOf ("in"); - if (inIndex > input.length() - 3) - { - *error = kParseErrorMissingSlopeFinalValue; - return retval; - } - if (inIndex < 0) { *error = kParseErrorMissingSlopeLengthDelimiter; return retval; } + if (inIndex > input.length() - 3) + { + *error = kParseErrorMissingSlopeFrameCount; + return retval; + } + if (inIndex - toIndex < 3) + { + *error = kParseErrorMissingSlopeFinalValue; + return retval; + } + // get 3 substrings separated by "to" and "in" and put them into `from`, `to`, `cntStr` String fromStr = input.substring (0, toIndex); String toStr = input.substring (toIndex + 2, inIndex); From 60068f313a6b0a21c8bd7ba110d6c44d3e41d485 Mon Sep 17 00:00:00 2001 From: Takeshi Yokemura Date: Sun, 15 Aug 2021 15:58:46 +0900 Subject: [PATCH 5/9] Hold Parser test (and related renames) --- Source/EnvelopeParserTest.h | 30 ++++++++++++++++++++++++----- Source/FrameSequenceParseErrors.cpp | 4 ++-- Source/FrameSequenceParseErrors.h | 4 ++-- Source/FrameSequenceParser.cpp | 10 +++++----- Source/FrameSequenceParser.h | 2 +- 5 files changed, 35 insertions(+), 15 deletions(-) diff --git a/Source/EnvelopeParserTest.h b/Source/EnvelopeParserTest.h index d9f8043..b860700 100644 --- a/Source/EnvelopeParserTest.h +++ b/Source/EnvelopeParserTest.h @@ -121,6 +121,7 @@ public: beginTest ("Down slope"); String input14 = "3to0in4"; std::vector result14 = parser.parseSlope(input14, 0, 15, &error); + expect(result14.size() == 4); expect(result14[0] == 3); expect(result14[1] == 2); expect(result14[2] == 1); @@ -129,6 +130,7 @@ public: beginTest ("Slow decrement"); String input15 = "2to0in8"; std::vector result15 = parser.parseSlope(input15, 0, 15, &error); + expect(result15.size() == 8); expect(result15[0] == 2); expect(result15[1] == 2); expect(result15[2] == 1); @@ -141,6 +143,7 @@ public: beginTest ("Fast decrement"); String input16 = "15to0in5"; std::vector result16 = parser.parseSlope(input16, 0, 15, &error); + expect(result16.size() == 5); expect(result16[0] == 15); expect(result16[1] == 11); expect(result16[2] == 8); @@ -150,6 +153,7 @@ public: beginTest ("Up slope"); String input17 = "0to3in4"; std::vector result17 = parser.parseSlope(input17, 0, 15, &error); + expect(result17.size() == 4); expect(result17[0] == 0); expect(result17[1] == 1); expect(result17[2] == 2); @@ -175,12 +179,28 @@ public: std::vector result21 = parser.parseSlope(input21, 0, 15, &error); expect(error == kParseErrorMissingSlopeFrameCount); + //------------------------------------------------------- + // + // Hold + // + //------------------------------------------------------- + beginTest ("Hold"); + String input22 = "15x3"; + std::vector result22 = parser.parseHold(input22, 0, 15, &error); + expect(result22.size() == 3); + expect(result22[0] == 15); + expect(result22[1] == 15); + expect(result22[2] == 15); - //------------------------------------------------------- - // - // Repeat - // - //------------------------------------------------------- + beginTest ("[Error] Missing value"); + String input23 = "x3"; + std::vector result23 = parser.parseHold(input23, 0, 15, &error); + expect(error == kParseErrorMissingHoldValue); + + beginTest ("[Error] Missing value"); + String input24 = "3x"; + std::vector result24 = parser.parseHold(input24, 0, 15, &error); + expect(error == kParseErrorMissingHoldFrameCount); //------------------------------------------------------- // diff --git a/Source/FrameSequenceParseErrors.cpp b/Source/FrameSequenceParseErrors.cpp index 49e4553..84cbc03 100644 --- a/Source/FrameSequenceParseErrors.cpp +++ b/Source/FrameSequenceParseErrors.cpp @@ -70,11 +70,11 @@ String getParseErrorString (ParseError err, int minValue, int maxValue) return TRANS ("Frame count should be more than 2"); break; - case kParseErrorMissingValueForRepeatDelimiter: + case kParseErrorMissingHoldValue: return TRANS ("Operator x should be followed by a number."); break; - case kParseErrorMissingFrameCountForRepeatDelimiter: + case kParseErrorMissingHoldFrameCount: return TRANS ("A number should be specified after operator x."); break; diff --git a/Source/FrameSequenceParseErrors.h b/Source/FrameSequenceParseErrors.h index a65a076..3afa5fe 100644 --- a/Source/FrameSequenceParseErrors.h +++ b/Source/FrameSequenceParseErrors.h @@ -31,8 +31,8 @@ enum ParseError kParseErrorNotANumber, kParseErrorValueOutOfRange, kParseErrorFrameLengthTooShort, - kParseErrorMissingValueForRepeatDelimiter, - kParseErrorMissingFrameCountForRepeatDelimiter, + kParseErrorMissingHoldValue, + kParseErrorMissingHoldFrameCount, }; String getParseErrorString (ParseError err, int minValue = 0, int maxValue = 0); diff --git a/Source/FrameSequenceParser.cpp b/Source/FrameSequenceParser.cpp index c3807a5..00ae721 100644 --- a/Source/FrameSequenceParser.cpp +++ b/Source/FrameSequenceParser.cpp @@ -116,7 +116,7 @@ std::vector FrameSequenceParser::parseSlope (const String& input, return retval; } -std::vector FrameSequenceParser::parseRepeat (const String& input, +std::vector FrameSequenceParser::parseHold (const String& input, int minValue, int maxValue, ParseError* error) @@ -127,13 +127,13 @@ std::vector FrameSequenceParser::parseRepeat (const String& input, if (xIndex < 1) { - *error = kParseErrorMissingValueForRepeatDelimiter; + *error = kParseErrorMissingHoldValue; return retval; } - if (xIndex > input.length() - 1) + if (xIndex >= input.length() - 1) { - *error = kParseErrorMissingFrameCountForRepeatDelimiter; + *error = kParseErrorMissingHoldFrameCount; return retval; } @@ -195,7 +195,7 @@ std::vector FrameSequenceParser::parseSegment (const String& input, else if (aToken.contains ("x")) { // parse as repeat-fixed-value - parsed = parseRepeat (aToken, minValue, maxValue, error); + parsed = parseHold (aToken, minValue, maxValue, error); } else { diff --git a/Source/FrameSequenceParser.h b/Source/FrameSequenceParser.h index dccc77a..60cd77d 100644 --- a/Source/FrameSequenceParser.h +++ b/Source/FrameSequenceParser.h @@ -36,7 +36,7 @@ struct FrameSequenceParser int minValue, int maxValue, ParseError* error); - std::vector parseRepeat (const String& input, + std::vector parseHold (const String& input, int minValue, int maxValue, ParseError* error); From b1928a69297884be41ba9f0ef4dccbed0b06f5b9 Mon Sep 17 00:00:00 2001 From: Takeshi Yokemura Date: Sun, 15 Aug 2021 18:09:58 +0900 Subject: [PATCH 6/9] Test split string --- Source/EnvelopeParserTest.h | 75 ++++++++++++++++++++++++++++- Source/FrameSequenceParseErrors.cpp | 4 ++ Source/FrameSequenceParser.cpp | 74 ++++++++++++++++------------ Source/FrameSequenceParser.h | 5 ++ 4 files changed, 126 insertions(+), 32 deletions(-) diff --git a/Source/EnvelopeParserTest.h b/Source/EnvelopeParserTest.h index b860700..43d8842 100644 --- a/Source/EnvelopeParserTest.h +++ b/Source/EnvelopeParserTest.h @@ -28,12 +28,21 @@ public: // Section index // //------------------------------------------------------- + String str_beforeRepeat; + String str_insideRepeat; + String str_release; + beginTest ("No repeat"); String input1 = "aaa"; // At this phase it doesn't matter if it contains numbers or not auto result1 = parser.findSegment(input1); expect(result1.repeatStartIndex == SegmentIndexes::NONE); expect(result1.repeatEndIndex == SegmentIndexes::NONE); expect(result1.releaseBlockIndex == SegmentIndexes::NONE); + + parser.splitSegment(input1, result1, str_beforeRepeat, str_insideRepeat, str_release); + expect(str_beforeRepeat == "aaa"); + expect(str_insideRepeat == ""); + expect(str_release == ""); beginTest ("With repeat, no release"); String input2 = "aa[bbb]"; @@ -42,6 +51,14 @@ public: expect(result2.repeatEndIndex == 6); expect(result2.releaseBlockIndex == SegmentIndexes::NONE); + str_beforeRepeat = ""; + str_insideRepeat = ""; + str_release = ""; + parser.splitSegment(input2, result2, str_beforeRepeat, str_insideRepeat, str_release); + expect(str_beforeRepeat == "aa"); + expect(str_insideRepeat == "bbb"); + expect(str_release == ""); + beginTest ("Repeat segment starts from the top"); String input3 = "[aaa]"; auto result3 = parser.findSegment(input3); @@ -49,6 +66,14 @@ public: expect(result3.repeatEndIndex == 4); expect(result3.releaseBlockIndex == SegmentIndexes::NONE); + str_beforeRepeat = ""; + str_insideRepeat = ""; + str_release = ""; + parser.splitSegment(input3, result3, str_beforeRepeat, str_insideRepeat, str_release); + expect(str_beforeRepeat == ""); + expect(str_insideRepeat == "aaa"); + expect(str_release == ""); + beginTest ("No repeat, with release"); String input4 = "aaa|bbbb"; auto result4 = parser.findSegment(input4); @@ -56,6 +81,14 @@ public: expect(result4.repeatEndIndex == 3); // It doesn't repeat, but it has to keep the last index of pre-release segment expect(result4.releaseBlockIndex == 4); + str_beforeRepeat = ""; + str_insideRepeat = ""; + str_release = ""; + parser.splitSegment(input4, result4, str_beforeRepeat, str_insideRepeat, str_release); + expect(str_beforeRepeat == "aaa"); + expect(str_insideRepeat == ""); + expect(str_release == "bbbb"); + beginTest ("Release segment without pre-release segment"); String input5 = "|bbbb"; auto result5 = parser.findSegment(input5); @@ -63,6 +96,14 @@ public: expect(result5.repeatEndIndex == 0); // This results in an immediate transition to Release Phase expect(result5.releaseBlockIndex == 1); + str_beforeRepeat = ""; + str_insideRepeat = ""; + str_release = ""; + parser.splitSegment(input5, result5, str_beforeRepeat, str_insideRepeat, str_release); + expect(str_beforeRepeat == ""); + expect(str_insideRepeat == ""); + expect(str_release == "bbbb"); + beginTest ("Repeat and release (no pre-repeat)"); String input6 = "[aaa]|bbbb"; auto result6 = parser.findSegment(input6); @@ -70,6 +111,14 @@ public: expect(result6.repeatEndIndex == 4); expect(result6.releaseBlockIndex == 6); + str_beforeRepeat = ""; + str_insideRepeat = ""; + str_release = ""; + parser.splitSegment(input6, result6, str_beforeRepeat, str_insideRepeat, str_release); + expect(str_beforeRepeat == ""); + expect(str_insideRepeat == "aaa"); + expect(str_release == "bbbb"); + beginTest ("Repeat and release (with pre-repeat)"); String input7 = "aaa[bbb]|cccc"; auto result7 = parser.findSegment(input7); @@ -77,6 +126,14 @@ public: expect(result7.repeatEndIndex == 7); expect(result7.releaseBlockIndex == 9); + str_beforeRepeat = ""; + str_insideRepeat = ""; + str_release = ""; + parser.splitSegment(input7, result7, str_beforeRepeat, str_insideRepeat, str_release); + expect(str_beforeRepeat == "aaa"); + expect(str_insideRepeat == "bbb"); + expect(str_release == "cccc"); + beginTest ("Empty repeat section"); String input8 = "aaa[]|cccc"; auto result8 = parser.findSegment(input8); @@ -84,6 +141,14 @@ public: expect(result8.repeatEndIndex == 4); expect(result8.releaseBlockIndex == 6); + str_beforeRepeat = ""; + str_insideRepeat = ""; + str_release = ""; + parser.splitSegment(input8, result8, str_beforeRepeat, str_insideRepeat, str_release); + expect(str_beforeRepeat == "aaa"); + expect(str_insideRepeat == ""); + expect(str_release == "cccc"); + beginTest ("Empty release section"); String input9 = "aaa[bbb]|"; auto result9 = parser.findSegment(input9); @@ -91,6 +156,14 @@ public: expect(result9.repeatEndIndex == 7); expect(result9.releaseBlockIndex == 9); + str_beforeRepeat = ""; + str_insideRepeat = ""; + str_release = ""; + parser.splitSegment(input9, result9, str_beforeRepeat, str_insideRepeat, str_release); + expect(str_beforeRepeat == "aaa"); + expect(str_insideRepeat == "bbb"); + expect(str_release == ""); + beginTest ("[Error] Multiple open bracket"); String input10 = "aaa[[bbb]"; auto result10 = parser.findSegment(input10); @@ -110,7 +183,7 @@ public: String input13 = "aaa|[bbb]"; auto result13 = parser.findSegment(input13); expect(result13.error = kParseErrorRepeatingInReleaseBlock); - + //------------------------------------------------------- // // Slope diff --git a/Source/FrameSequenceParseErrors.cpp b/Source/FrameSequenceParseErrors.cpp index 84cbc03..8e05e4f 100644 --- a/Source/FrameSequenceParseErrors.cpp +++ b/Source/FrameSequenceParseErrors.cpp @@ -58,6 +58,10 @@ String getParseErrorString (ParseError err, int minValue, int maxValue) return TRANS ("Missing destination value before \"in\""); break; + case kParseErrorMissingSlopeFrameCount: + return TRANS ("Frame count should be specified after \"in\""); + break; + case kParseErrorNotANumber: return TRANS ("Number parse failed."); break; diff --git a/Source/FrameSequenceParser.cpp b/Source/FrameSequenceParser.cpp index 00ae721..e6ba71d 100644 --- a/Source/FrameSequenceParser.cpp +++ b/Source/FrameSequenceParser.cpp @@ -344,6 +344,46 @@ SegmentIndexes FrameSequenceParser::findSegment(const String& input) { return retval; } +void FrameSequenceParser::splitSegment (const String& input, + SegmentIndexes indexes, + String& beforeRepeat, + String& insideRepeat, + String& afterRelease) { + int releaseBlockIndex = indexes.releaseBlockIndex; + int repeatStartIndex = indexes.repeatStartIndex; + int repeatEndIndex = indexes.repeatEndIndex; + + // Just for convenience + bool hasRelease = (releaseBlockIndex >= 0); + bool shouldRepeat = (repeatStartIndex >= 0); + + if (shouldRepeat) + { + if (hasRelease) + { + beforeRepeat = input.substring(0, repeatStartIndex - 1); + insideRepeat = input.substring (repeatStartIndex, repeatEndIndex); + afterRelease = input.substring(releaseBlockIndex, input.length()); + } + else + { + beforeRepeat = input.substring(0, repeatStartIndex - 1); + insideRepeat = input.substring (repeatStartIndex, repeatEndIndex); + } + } + else + { + if (hasRelease) { + beforeRepeat = input.substring (0, releaseBlockIndex - 1); + afterRelease = input.substring (releaseBlockIndex, input.length()); + } + else + { + beforeRepeat = input.substring (0, input.length()); + } + } +} + FrameSequence FrameSequenceParser::parse (const String& input, int minValue, int maxValue, @@ -366,13 +406,9 @@ FrameSequence FrameSequenceParser::parse (const String& input, // SegmentIndexes si = findSegment(trimmed); - int releaseBlockIndex = si.releaseBlockIndex; - int repeatStartIndex = si.repeatStartIndex; - int repeatEndIndex = si.repeatEndIndex; - // Just for convenience - bool hasRelease = (releaseBlockIndex >= 0); - bool shouldRepeat = (repeatStartIndex >= 0); + bool hasRelease = (si.releaseBlockIndex >= 0); + bool shouldRepeat = (si.repeatStartIndex >= 0); //----------------------------------- // @@ -384,31 +420,7 @@ FrameSequence FrameSequenceParser::parse (const String& input, String str_insideRepeat; String str_release; - if (shouldRepeat) - { - if (hasRelease) - { - str_release = trimmed.substring(releaseBlockIndex, trimmed.length()); - } - str_beforeRepeat = trimmed.substring(0, repeatStartIndex - 1); - str_insideRepeat = trimmed.substring (repeatStartIndex, repeatEndIndex); } - else - { - if (hasRelease) - { - str_beforeRepeat = trimmed.substring (0, releaseBlockIndex - 1); - str_release = trimmed.substring (releaseBlockIndex, trimmed.length()); - } - else - { - str_beforeRepeat = trimmed.substring (0, trimmed.length()); - } - } - - std::cout << "before repeat : " + str_beforeRepeat + "\n"; - std::cout << "inside repeat : " + str_insideRepeat + "\n"; - std::cout << "after release : " + str_release + "\n"; - + splitSegment(trimmed, si, str_beforeRepeat, str_insideRepeat, str_release); //----------------------------------- // diff --git a/Source/FrameSequenceParser.h b/Source/FrameSequenceParser.h index 60cd77d..420e6de 100644 --- a/Source/FrameSequenceParser.h +++ b/Source/FrameSequenceParser.h @@ -44,5 +44,10 @@ struct FrameSequenceParser int minValue, int maxValue, ParseError* error); + void splitSegment (const String& input, + SegmentIndexes indexes, + String& beforeRepeat, + String& insideRepeat, + String& afterRelease); SegmentIndexes findSegment(const String& input); }; From 2b973155b00d0fc567faaf6a5b13f75242101679 Mon Sep 17 00:00:00 2001 From: Takeshi Yokemura Date: Sun, 15 Aug 2021 18:29:54 +0900 Subject: [PATCH 7/9] Overall test --- Source/EnvelopeParserTest.h | 39 +++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/Source/EnvelopeParserTest.h b/Source/EnvelopeParserTest.h index 43d8842..11d5c1e 100644 --- a/Source/EnvelopeParserTest.h +++ b/Source/EnvelopeParserTest.h @@ -280,6 +280,45 @@ public: // Total // //------------------------------------------------------- + beginTest ("Overall test"); + error = kParseErrorNone; + String input25 = "1, 2x2, 3to4in2 [5, 6]|7, 8"; + FrameSequence result25 = parser.parse(input25, 0, 15, &error); + expect(result25.valueAt(0) == 1); + expect(result25.valueAt(1) == 2); + expect(result25.valueAt(2) == 2); + expect(result25.valueAt(3) == 3); + expect(result25.valueAt(4) == 4); + expect(result25.valueAt(5) == 5); + expect(result25.valueAt(6) == 6); + expect(result25.valueAt(7) == 7); + expect(result25.valueAt(8) == 8); + expect(result25.loopStartIndex = 5); + expect(result25.releaseSequenceStartIndex = 7); + + beginTest ("Value error"); + error = kParseErrorNone; + String input26 = "1, 2, 3"; + FrameSequence result26 = parser.parse(input26, 0, 2, &error); + expect(error = kParseErrorValueOutOfRange); + + beginTest ("Value error - under"); + error = kParseErrorNone; + String input27 = "1, 2, 3"; + FrameSequence result27 = parser.parse(input27, 2, 3, &error); + expect(error = kParseErrorValueOutOfRange); + + beginTest ("Value error2"); + error = kParseErrorNone; + String input28 = "1, 2, 3x2"; + FrameSequence result28 = parser.parse(input28, 0, 2, &error); + expect(error = kParseErrorValueOutOfRange); + + beginTest ("Value error3"); + error = kParseErrorNone; + String input29 = "1, 2, 0to3in2"; + FrameSequence result29 = parser.parse(input29, 0, 2, &error); + expect(error = kParseErrorValueOutOfRange); } }; From 411d3b4868a128aaec3b02c7ec2df356fdd2d8cd Mon Sep 17 00:00:00 2001 From: Takeshi Yokemura Date: Sun, 15 Aug 2021 18:50:29 +0900 Subject: [PATCH 8/9] Added new parse warning message --- Source/CustomEnvelopeComponent.cpp | 4 ++++ Source/FrameSequenceParseErrors.cpp | 12 ++++++++++++ Source/FrameSequenceParseErrors.h | 3 +++ Source/FrameSequenceParser.cpp | 11 +++++++++++ 4 files changed, 30 insertions(+) diff --git a/Source/CustomEnvelopeComponent.cpp b/Source/CustomEnvelopeComponent.cpp index fcefe30..aa43be5 100644 --- a/Source/CustomEnvelopeComponent.cpp +++ b/Source/CustomEnvelopeComponent.cpp @@ -153,6 +153,10 @@ void CustomEnvelopeComponent::textEditorTextChanged (TextEditor& editor) ParseError err = kParseErrorNone; processor.settingRefs.setSequenceWithString (paramType, txt, &err); + + ColorScheme cs = ColorScheme (processor.settingRefs.colorSchemeType()); + Colour c = (err < kParseErrorLevelFatal) ? cs.main : cs.warning; + label->setColour (juce::Label::textColourId, c); if (err == kParseErrorValueOutOfRange) { diff --git a/Source/FrameSequenceParseErrors.cpp b/Source/FrameSequenceParseErrors.cpp index 8e05e4f..3e7cd37 100644 --- a/Source/FrameSequenceParseErrors.cpp +++ b/Source/FrameSequenceParseErrors.cpp @@ -14,6 +14,18 @@ String getParseErrorString (ParseError err, int minValue, int maxValue) { switch (err) { + case kParseWarningPreRepeatSegmentEmpty: + return TRANS ("Main body of the sequence is empty"); + break; + + case kParseWarningRepeatSegmentEmpty: + return TRANS ("Repeat section is empty"); + break; + + case kParseWarningReleaseSegmentEmpty: + return TRANS ("Release section is empty"); + break; + case kParseErrorDuplicatedReleaseDelimiter: return TRANS ("You cannot use \"|\" more than once"); break; diff --git a/Source/FrameSequenceParseErrors.h b/Source/FrameSequenceParseErrors.h index 3afa5fe..db6ca3a 100644 --- a/Source/FrameSequenceParseErrors.h +++ b/Source/FrameSequenceParseErrors.h @@ -15,6 +15,9 @@ enum ParseError { kParseErrorNone = 0, kParseErrorLevelWarning, + kParseWarningPreRepeatSegmentEmpty, + kParseWarningRepeatSegmentEmpty, + kParseWarningReleaseSegmentEmpty, kParseErrorLevelFatal, kParseErrorDuplicatedReleaseDelimiter, kParseErrorDuplicatedOpenBracket, diff --git a/Source/FrameSequenceParser.cpp b/Source/FrameSequenceParser.cpp index e6ba71d..d1f4350 100644 --- a/Source/FrameSequenceParser.cpp +++ b/Source/FrameSequenceParser.cpp @@ -438,6 +438,9 @@ FrameSequence FrameSequenceParser::parse (const String& input, { return fs; } + if (sequence.size() == 0) { + *error = kParseWarningPreRepeatSegmentEmpty; + } fs.sequence = sequence; fs.sequence.reserve (1000); @@ -456,6 +459,10 @@ FrameSequence FrameSequenceParser::parse (const String& input, { return fs; } + if (repeatSeq.size() == 0) { + // Repeat section is defined but content is empty + *error = kParseWarningRepeatSegmentEmpty; + } // Add the result to working frameSequence fs.sequence.insert (fs.sequence.end(), repeatSeq.begin(), repeatSeq.end()); @@ -477,6 +484,10 @@ FrameSequence FrameSequenceParser::parse (const String& input, { return fs; } + if (releaseSeq.size() == 0) { + // Release section is defined but content is empty + *error = kParseWarningRepeatSegmentEmpty; + } // Add the result to working frameSequence fs.sequence.insert (fs.sequence.end(), releaseSeq.begin(), releaseSeq.end()); From 5feee3b6ecd59ccad4046b9dc2c6e49016eb1cad Mon Sep 17 00:00:00 2001 From: Takeshi Yokemura Date: Sun, 15 Aug 2021 19:40:14 +0900 Subject: [PATCH 9/9] Added warnings test --- Source/EnvelopeParserTest.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Source/EnvelopeParserTest.h b/Source/EnvelopeParserTest.h index 11d5c1e..a601ded 100644 --- a/Source/EnvelopeParserTest.h +++ b/Source/EnvelopeParserTest.h @@ -320,5 +320,35 @@ public: FrameSequence result29 = parser.parse(input29, 0, 2, &error); expect(error = kParseErrorValueOutOfRange); + beginTest ("Empty segment warning(pre-repeat)"); + error = kParseErrorNone; + String input30 = "[1]|2"; + FrameSequence result30 = parser.parse(input30, 0, 2, &error); + expect(result30.valueAt(0) == 1); + expect(result30.valueAt(1) == 2); + expect(result30.loopStartIndex == 0); + expect(result30.releaseSequenceStartIndex == 1); + expect(error = kParseWarningPreRepeatSegmentEmpty); + + beginTest ("Empty segment warning(in-repeat)"); + error = kParseErrorNone; + String input31 = "1[]|2"; + FrameSequence result31 = parser.parse(input31, 0, 2, &error); + expect(result31.valueAt(0) == 1); + expect(result31.valueAt(1) == 2); + expect(result31.loopStartIndex == 1); + expect(result31.releaseSequenceStartIndex == 1); + expect(error = kParseWarningRepeatSegmentEmpty); + + beginTest ("Empty segment warning(after release)"); + error = kParseErrorNone; + String input32 = "1[2]|"; + FrameSequence result32 = parser.parse(input32, 0, 2, &error); + expect(result32.valueAt(0) == 1); + expect(result32.valueAt(1) == 2); + expect(result32.loopStartIndex == 1); + expect(result32.releaseSequenceStartIndex == 2); + expect(error = kParseWarningReleaseSegmentEmpty); + } };