mirror of
https://github.com/yokemura/Magical8bitPlug2.git
synced 2025-05-24 23:00:21 -04:00
Merge branch 'develop' into feature/monoMode
This commit is contained in:
commit
ef6d94654c
@ -10,6 +10,10 @@
|
||||
pluginDesc="8bit sound generator 2nd ver. by YMCK" displaySplashScreen="1"
|
||||
jucerFormatVersion="1" version="1.0.1">
|
||||
<MAINGROUP id="tlJ5Jv" name="Magical8bitPlug2">
|
||||
<GROUP id="{90CFFF6B-201B-9373-6BE8-DDF2F136949F}" name="Tests">
|
||||
<FILE id="WZca8g" name="EnvelopeParserTest.h" compile="0" resource="0"
|
||||
file="Source/EnvelopeParserTest.h"/>
|
||||
</GROUP>
|
||||
<GROUP id="{05934500-901F-8317-27DC-7E17FC00833D}" name="View">
|
||||
<GROUP id="{68A7410F-88F9-C9D8-8A37-6A70F269BBCC}" name="BaseComponents">
|
||||
<FILE id="lBYKKS" name="CheckBoxComponent.cpp" compile="1" resource="0"
|
||||
|
@ -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)
|
||||
{
|
||||
|
354
Source/EnvelopeParserTest.h
Normal file
354
Source/EnvelopeParserTest.h
Normal file
@ -0,0 +1,354 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
EnvelopeParserTest.h
|
||||
Created: 13 Aug 2021 6:14:32pm
|
||||
Author: 除村武志
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../JuceLibraryCode/JuceHeader.h"
|
||||
#include "FrameSequence.h"
|
||||
#include "FrameSequenceParser.h"
|
||||
#include "FrameSequenceParseErrors.h"
|
||||
|
||||
class EnvelopeParserTest : public UnitTest {
|
||||
|
||||
public:
|
||||
EnvelopeParserTest() : UnitTest("Custom Envelope Parser Test") {}
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
FrameSequenceParser parser;
|
||||
|
||||
//-------------------------------------------------------
|
||||
//
|
||||
// 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]";
|
||||
auto result2 = parser.findSegment(input2);
|
||||
expect(result2.repeatStartIndex == 3);
|
||||
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);
|
||||
expect(result3.repeatStartIndex == 1);
|
||||
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);
|
||||
expect(result4.repeatStartIndex == SegmentIndexes::NONE);
|
||||
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);
|
||||
expect(result5.repeatStartIndex == SegmentIndexes::NONE);
|
||||
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);
|
||||
expect(result6.repeatStartIndex == 1);
|
||||
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);
|
||||
expect(result7.repeatStartIndex == 4);
|
||||
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);
|
||||
expect(result8.repeatStartIndex == 4);
|
||||
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);
|
||||
expect(result9.repeatStartIndex == 4);
|
||||
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);
|
||||
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<int> result14 = parser.parseSlope(input14, 0, 15, &error);
|
||||
expect(result14.size() == 4);
|
||||
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<int> result15 = parser.parseSlope(input15, 0, 15, &error);
|
||||
expect(result15.size() == 8);
|
||||
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<int> result16 = parser.parseSlope(input16, 0, 15, &error);
|
||||
expect(result16.size() == 5);
|
||||
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<int> result17 = parser.parseSlope(input17, 0, 15, &error);
|
||||
expect(result17.size() == 4);
|
||||
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<int> result18 = parser.parseSlope(input18, 0, 15, &error);
|
||||
expect(error == kParseErrorMissingSlopeLengthDelimiter);
|
||||
|
||||
beginTest ("[Error] Missing initial value");
|
||||
String input19 = "to5in5";
|
||||
std::vector<int> result19 = parser.parseSlope(input19, 0, 15, &error);
|
||||
expect(error == kParseErrorMissingSlopeInitialValue);
|
||||
|
||||
beginTest ("[Error] Missing final value");
|
||||
String input20 = "4toin5";
|
||||
std::vector<int> result20 = parser.parseSlope(input20, 0, 15, &error);
|
||||
expect(error == kParseErrorMissingSlopeFinalValue);
|
||||
|
||||
beginTest ("[Error] Missing frame count");
|
||||
String input21 = "0to3in";
|
||||
std::vector<int> result21 = parser.parseSlope(input21, 0, 15, &error);
|
||||
expect(error == kParseErrorMissingSlopeFrameCount);
|
||||
|
||||
//-------------------------------------------------------
|
||||
//
|
||||
// Hold
|
||||
//
|
||||
//-------------------------------------------------------
|
||||
beginTest ("Hold");
|
||||
String input22 = "15x3";
|
||||
std::vector<int> result22 = parser.parseHold(input22, 0, 15, &error);
|
||||
expect(result22.size() == 3);
|
||||
expect(result22[0] == 15);
|
||||
expect(result22[1] == 15);
|
||||
expect(result22[2] == 15);
|
||||
|
||||
beginTest ("[Error] Missing value");
|
||||
String input23 = "x3";
|
||||
std::vector<int> result23 = parser.parseHold(input23, 0, 15, &error);
|
||||
expect(error == kParseErrorMissingHoldValue);
|
||||
|
||||
beginTest ("[Error] Missing value");
|
||||
String input24 = "3x";
|
||||
std::vector<int> result24 = parser.parseHold(input24, 0, 15, &error);
|
||||
expect(error == kParseErrorMissingHoldFrameCount);
|
||||
|
||||
//-------------------------------------------------------
|
||||
//
|
||||
// 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);
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
};
|
@ -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;
|
||||
@ -58,6 +70,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;
|
||||
@ -70,11 +86,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;
|
||||
|
||||
|
@ -15,6 +15,9 @@ enum ParseError
|
||||
{
|
||||
kParseErrorNone = 0,
|
||||
kParseErrorLevelWarning,
|
||||
kParseWarningPreRepeatSegmentEmpty,
|
||||
kParseWarningRepeatSegmentEmpty,
|
||||
kParseWarningReleaseSegmentEmpty,
|
||||
kParseErrorLevelFatal,
|
||||
kParseErrorDuplicatedReleaseDelimiter,
|
||||
kParseErrorDuplicatedOpenBracket,
|
||||
@ -27,11 +30,12 @@ enum ParseError
|
||||
kParseErrorMissingSlopeLengthDelimiter,
|
||||
kParseErrorMissingSlopeInitialValue,
|
||||
kParseErrorMissingSlopeFinalValue,
|
||||
kParseErrorMissingSlopeFrameCount,
|
||||
kParseErrorNotANumber,
|
||||
kParseErrorValueOutOfRange,
|
||||
kParseErrorFrameLengthTooShort,
|
||||
kParseErrorMissingValueForRepeatDelimiter,
|
||||
kParseErrorMissingFrameCountForRepeatDelimiter,
|
||||
kParseErrorMissingHoldValue,
|
||||
kParseErrorMissingHoldFrameCount,
|
||||
};
|
||||
|
||||
String getParseErrorString (ParseError err, int minValue = 0, int maxValue = 0);
|
||||
|
@ -10,11 +10,7 @@
|
||||
|
||||
#include "FrameSequenceParser.h"
|
||||
|
||||
//
|
||||
// Fileprivate
|
||||
//
|
||||
|
||||
std::vector<int> parseSlope (const String& input,
|
||||
std::vector<int> FrameSequenceParser::parseSlope (const String& input,
|
||||
int minValue,
|
||||
int maxValue,
|
||||
ParseError* error)
|
||||
@ -40,18 +36,23 @@ std::vector<int> 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);
|
||||
@ -115,7 +116,7 @@ std::vector<int> parseSlope (const String& input,
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::vector<int> parseRepeat (const String& input,
|
||||
std::vector<int> FrameSequenceParser::parseHold (const String& input,
|
||||
int minValue,
|
||||
int maxValue,
|
||||
ParseError* error)
|
||||
@ -126,13 +127,13 @@ std::vector<int> 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;
|
||||
}
|
||||
|
||||
@ -172,7 +173,7 @@ std::vector<int> parseRepeat (const String& input,
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::vector<int> parseSegment (const String& input,
|
||||
std::vector<int> FrameSequenceParser::parseSegment (const String& input,
|
||||
int minValue,
|
||||
int maxValue,
|
||||
ParseError* error)
|
||||
@ -194,7 +195,7 @@ std::vector<int> 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
|
||||
{
|
||||
@ -228,6 +229,161 @@ std::vector<int> parseSegment (const String& input,
|
||||
return retval;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
@ -248,116 +404,11 @@ FrameSequence FrameSequenceParser::parse (const String& input,
|
||||
//
|
||||
// Overall structure
|
||||
//
|
||||
|
||||
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をどう扱うか
|
||||
}
|
||||
SegmentIndexes si = findSegment(trimmed);
|
||||
|
||||
// Just for convenience
|
||||
bool hasRelease = (releaseBlockIndex >= 0);
|
||||
bool shouldRepeat = (repeatStartIndex >= 0);
|
||||
bool hasRelease = (si.releaseBlockIndex >= 0);
|
||||
bool shouldRepeat = (si.repeatStartIndex >= 0);
|
||||
|
||||
//-----------------------------------
|
||||
//
|
||||
@ -369,32 +420,7 @@ FrameSequence FrameSequenceParser::parse (const String& input,
|
||||
String str_insideRepeat;
|
||||
String str_release;
|
||||
|
||||
if (shouldRepeat)
|
||||
{
|
||||
if (hasRelease)
|
||||
{
|
||||
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);
|
||||
|
||||
//-----------------------------------
|
||||
//
|
||||
@ -412,6 +438,9 @@ FrameSequence FrameSequenceParser::parse (const String& input,
|
||||
{
|
||||
return fs;
|
||||
}
|
||||
if (sequence.size() == 0) {
|
||||
*error = kParseWarningPreRepeatSegmentEmpty;
|
||||
}
|
||||
|
||||
fs.sequence = sequence;
|
||||
fs.sequence.reserve (1000);
|
||||
@ -430,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());
|
||||
@ -451,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());
|
||||
|
@ -13,7 +13,41 @@
|
||||
#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
|
||||
{
|
||||
/*
|
||||
Public
|
||||
*/
|
||||
FrameSequence parse (const String& input, int minValue, int maxValue, ParseError* error);
|
||||
|
||||
/*
|
||||
Semantically private (leave them open for unit testing)
|
||||
*/
|
||||
std::vector<int> parseSlope (const String& input,
|
||||
int minValue,
|
||||
int maxValue,
|
||||
ParseError* error);
|
||||
std::vector<int> parseHold (const String& input,
|
||||
int minValue,
|
||||
int maxValue,
|
||||
ParseError* error);
|
||||
std::vector<int> parseSegment (const String& input,
|
||||
int minValue,
|
||||
int maxValue,
|
||||
ParseError* error);
|
||||
void splitSegment (const String& input,
|
||||
SegmentIndexes indexes,
|
||||
String& beforeRepeat,
|
||||
String& insideRepeat,
|
||||
String& afterRelease);
|
||||
SegmentIndexes findSegment(const String& input);
|
||||
};
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "TriangleVoice.h"
|
||||
#include "NoiseVoice.h"
|
||||
#include "FrameSequenceParseErrors.h"
|
||||
#include "EnvelopeParserTest.h"
|
||||
|
||||
//==============================================================================
|
||||
Magical8bitPlug2AudioProcessor::Magical8bitPlug2AudioProcessor()
|
||||
@ -121,7 +122,7 @@ Magical8bitPlug2AudioProcessor::Magical8bitPlug2AudioProcessor()
|
||||
std::make_unique<AudioParameterBool> ("isPitchSequenceEnabled_raw", "Enabled", false),
|
||||
std::make_unique<AudioParameterBool> ("isDutySequenceEnabled_raw", "Enabled", false),
|
||||
std::make_unique<AudioParameterChoice> ("pitchSequenceMode_raw", "Mode", StringArray ({"Coarse", "Fine"}), 0)
|
||||
}
|
||||
}
|
||||
)
|
||||
, settingRefs (¶meters)
|
||||
, synth(*this)
|
||||
@ -140,6 +141,12 @@ Magical8bitPlug2AudioProcessor::Magical8bitPlug2AudioProcessor()
|
||||
|
||||
setupVoice();
|
||||
synth.addSound (new GenericSound());
|
||||
|
||||
#if JUCE_DEBUG
|
||||
EnvelopeParserTest test;
|
||||
UnitTestRunner runner;
|
||||
runner.runAllTests();
|
||||
#endif
|
||||
}
|
||||
|
||||
Magical8bitPlug2AudioProcessor::~Magical8bitPlug2AudioProcessor()
|
||||
|
Loading…
Reference in New Issue
Block a user