diff --git a/midica.jar b/midica.jar index 4bf9537..46e32f1 100644 Binary files a/midica.jar and b/midica.jar differ diff --git a/src/org/midica/Midica.java b/src/org/midica/Midica.java index a28bf45..9960b78 100644 --- a/src/org/midica/Midica.java +++ b/src/org/midica/Midica.java @@ -36,7 +36,7 @@ public class Midica { private static final int VERSION_MINOR = 11; /** UNIX timestamp of the last commit */ - public static final int COMMIT_TIME = 1708970595; + public static final int COMMIT_TIME = 1709317508; /** Branch name. Automatically changed by precommit.pl */ public static final String BRANCH = "sound-effects"; diff --git a/src/org/midica/config/Dict.java b/src/org/midica/config/Dict.java index 89074ac..2994a12 100644 --- a/src/org/midica/config/Dict.java +++ b/src/org/midica/config/Dict.java @@ -1761,6 +1761,7 @@ public class Dict { public static final String ERROR_FL_NOTE_NOT_SET = "error_fl_note_not_set"; public static final String ERROR_FL_NOTE_PAT_IDX_NAN = "error_fl_note_pat_idx_nan"; public static final String ERROR_FL_NOTE_PAT_IDX_TOO_HIGH = "error_fl_note_pat_idx_too_high"; + public static final String ERROR_FL_PENDING = "error_fl_pending"; public static final String ERROR_FUNC_NOT_SUPPORTED_BY_EFF = "error_func_not_supported_by_eff"; public static final String ERROR_FUNC_VAL_LOWER_MIN = "error_func_val_lower_min"; public static final String ERROR_FUNC_VAL_GREATER_MAX = "error_func_val_greater_max"; @@ -3587,6 +3588,7 @@ private static void initLanguageEnglish() { set( ERROR_FL_NOTE_NOT_SET, "The chosen effect needs a note to be set before you can use this function: " ); set( ERROR_FL_NOTE_PAT_IDX_NAN, "pattern index '%s' is not a number in this element: %s" ); set( ERROR_FL_NOTE_PAT_IDX_TOO_HIGH, "pattern index '%s' too high in this element: %s" ); + set( ERROR_FL_PENDING, "Pending effect flow found before this line.
Delete the useless parts of the flow." ); set( ERROR_FUNC_NOT_SUPPORTED_BY_EFF, "The chosen effect does not support this function: " ); set( ERROR_FUNC_VAL_LOWER_MIN, "Parameter '%s' is smaller than the minimum value (%s)" ); set( ERROR_FUNC_VAL_GREATER_MAX, "Parameter '%s' is greater than the maximum value (%s)" ); diff --git a/src/org/midica/file/read/Effect.java b/src/org/midica/file/read/Effect.java index 750ccb3..6277789 100644 --- a/src/org/midica/file/read/Effect.java +++ b/src/org/midica/file/read/Effect.java @@ -67,6 +67,7 @@ public class Effect { */ public static void init(MidicaPLParser rootParser) { parser = rootParser; + flow = null; // create and initialize special structures { @@ -434,8 +435,29 @@ else if (numberStr != null) { /** * Closes the current flow, if there is an open flow. + * + * @throws ParseException if the current flow is pending. + */ + public static void closeFlowIfPossible() throws ParseException { + + // check if there is a pending flow + if (flow != null && flow.isPending()) { + throw new ParseException(Dict.get(Dict.ERROR_FL_PENDING)); + } + + flow = null; + } + + /** + * Closes the current flow, if there is an open flow. + * + * Does **not** check if the flow is pending or not. + * + * Called after all parsing runs are finished, no matter if an exception is thrown or not. + * + * Does **not** throw a further exception. */ - public static void closeFlowIfPossible() { + public static void closeFlowAfterParsingFinished() { flow = null; } @@ -546,6 +568,8 @@ private static int parseGenericNumber(String numberStr, String numberLsb, int ma */ private static void applyFlowElement(String elemName, int number, String paramStr) throws ParseException { + flow.setPending(true); + // check presence of params if (functionNames.contains(elemName)) { if (paramStr == null && ! MidicaPLParser.FUNC_WAIT.equals(elemName)) @@ -707,6 +731,7 @@ private static void applyFunction(String funcName, String[] params) throws Parse // for all other functions we need the effect type int valueType = flow.getValueType(funcName); + flow.setPending(false); // note required but not set? if (flow.needsNote() && flow.getNote() < 0) diff --git a/src/org/midica/file/read/EffectFlow.java b/src/org/midica/file/read/EffectFlow.java index a948120..5b9779f 100644 --- a/src/org/midica/file/read/EffectFlow.java +++ b/src/org/midica/file/read/EffectFlow.java @@ -91,6 +91,7 @@ public class EffectFlow { private long ticksPerAction; private int effectType = 0; private int effectNumber = -1; + private boolean isPending = true; private boolean isDouble = false; private int note = -1; @@ -157,6 +158,32 @@ public int getEffectNumber() { return effectNumber; } + /** + * Marks the flow as pending or not pending. + * + * "Pending" means that the last called function was something like length(), wait(), note(), src(), dest() etc. + * + * "Not pending" means that the last called function was something like set(), on(), off(), line(), sin(), etc. + * + * @param isPending **true** for pending, **false** for not pending + */ + public void setPending(boolean isPending) { + this.isPending = isPending; + } + + /** + * Indicates if the flow is pending. + * + * "Pending" means that the last called function was something like length(), wait(), note(), src(), dest() etc. + * + * "Not pending" means that the last called function was something like set(), on(), off(), line(), sin(), etc. + * + * @return **true** if the flow is pending, otherwise: **false**. + */ + public boolean isPending() { + return isPending; + } + /** * Return all functions that are supported by the current effect type. * diff --git a/src/org/midica/file/read/MidicaPLParser.java b/src/org/midica/file/read/MidicaPLParser.java index 57e2e96..be68eaf 100644 --- a/src/org/midica/file/read/MidicaPLParser.java +++ b/src/org/midica/file/read/MidicaPLParser.java @@ -717,6 +717,12 @@ public void parse(Object fileAsObj) throws ParseException { e.printStackTrace(); throw new ParseException(e.toString()); } + finally { + // Close the flow. + // Avoids problems in the NEXT parsing attempt. + if (isRootParser) + Effect.closeFlowAfterParsingFinished(); + } // allow an empty sequence? if (isRootParser) { @@ -1017,6 +1023,9 @@ private void parsingRun(ArrayList lines) throws ParseException, IOExcept // In case of wrong block nesting make sure that the correct // error message and line number is shown nestableBlkDepth = 0; + + // check if a pending flow was the last command + Effect.closeFlowIfPossible(); } catch (ParseException e) { // Add file name and line number to exception and throw it again diff --git a/test/org/midica/file/read/MidicaPLParserTest.java b/test/org/midica/file/read/MidicaPLParserTest.java index 497162b..f2683e1 100644 --- a/test/org/midica/file/read/MidicaPLParserTest.java +++ b/test/org/midica/file/read/MidicaPLParserTest.java @@ -4116,32 +4116,32 @@ void testParseFilesFailing() { e = assertThrows( ParseException.class, () -> parse(getFailingFile("eff-flow-broken-by-var")) ); assertEquals( 6, e.getLineNumber() ); - assertEquals( "0: .set(50)", e.getLineContent() ); + assertEquals( "0: .wait.set(50)", e.getLineContent() ); assertTrue( e.getMessage().startsWith(String.format(Dict.get(Dict.ERROR_FL_NOT_OPEN), "."))); e = assertThrows( ParseException.class, () -> parse(getFailingFile("eff-flow-broken-by-const")) ); assertEquals( 6, e.getLineNumber() ); - assertEquals( "0: .set(50)", e.getLineContent() ); + assertEquals( "0: .wait.set(50)", e.getLineContent() ); assertTrue( e.getMessage().startsWith(String.format(Dict.get(Dict.ERROR_FL_NOT_OPEN), "."))); e = assertThrows( ParseException.class, () -> parse(getFailingFile("eff-flow-broken-by-call")) ); assertEquals( 6, e.getLineNumber() ); - assertEquals( "0: .set(50)", e.getLineContent() ); + assertEquals( "0: .wait.set(50)", e.getLineContent() ); assertTrue( e.getMessage().startsWith(String.format(Dict.get(Dict.ERROR_FL_NOT_OPEN), "."))); e = assertThrows( ParseException.class, () -> parse(getFailingFile("eff-flow-broken-by-function")) ); assertEquals( 7, e.getLineNumber() ); - assertEquals( "0: .set(50)", e.getLineContent() ); + assertEquals( "0: .wait.set(50)", e.getLineContent() ); assertTrue( e.getMessage().startsWith(String.format(Dict.get(Dict.ERROR_FL_NOT_OPEN), "."))); e = assertThrows( ParseException.class, () -> parse(getFailingFile("eff-flow-broken-by-note")) ); assertEquals( 6, e.getLineNumber() ); - assertEquals( "0: .set(50)", e.getLineContent() ); + assertEquals( "0: .wait.set(50)", e.getLineContent() ); assertTrue( e.getMessage().startsWith(String.format(Dict.get(Dict.ERROR_FL_NOT_OPEN), "."))); e = assertThrows( ParseException.class, () -> parse(getFailingFile("eff-flow-broken-by-other-channel")) ); assertEquals( 6, e.getLineNumber() ); - assertEquals( "0: .set(50)", e.getLineContent() ); + assertEquals( "0: .wait.set(50)", e.getLineContent() ); assertTrue( e.getMessage().startsWith(String.format(Dict.get(Dict.ERROR_FL_NOT_OPEN), "."))); e = assertThrows( ParseException.class, () -> parse(getFailingFile("eff-flow-missing-dot-1")) ); @@ -4658,6 +4658,26 @@ void testParseFilesFailing() { assertEquals( 4, e.getLineNumber() ); assertEquals( "0: mono_mode.set(+5)", e.getLineContent() ); assertTrue( e.getMessage().startsWith(Dict.get(Dict.ERROR_FUNC_SIGNED_FORBIDDEN) + "+5")); + + e = assertThrows( ParseException.class, () -> parse(getFailingFile("eff-flow-pending-1")) ); + assertEquals( 5, e.getLineNumber() ); + assertEquals( "1: c", e.getLineContent() ); + assertTrue( e.getMessage().startsWith(Dict.get(Dict.ERROR_FL_PENDING))); + + e = assertThrows( ParseException.class, () -> parse(getFailingFile("eff-flow-pending-2")) ); + assertEquals( 5, e.getLineNumber() ); + assertEquals( "0: hold.wait", e.getLineContent() ); + assertTrue( e.getMessage().startsWith(Dict.get(Dict.ERROR_FL_PENDING))); + + e = assertThrows( ParseException.class, () -> parse(getFailingFile("eff-flow-pending-3")) ); + assertEquals( 6, e.getLineNumber() ); + assertEquals( "", e.getLineContent() ); + assertTrue( e.getMessage().startsWith(Dict.get(Dict.ERROR_FL_PENDING))); + + e = assertThrows( ParseException.class, () -> parse(getFailingFile("eff-flow-pending-4")) ); + assertEquals( 23, e.getLineNumber() ); + assertEquals( "0: c", e.getLineContent() ); + assertTrue( e.getMessage().startsWith(Dict.get(Dict.ERROR_FL_PENDING))); } /** diff --git a/test/org/midica/testfiles/failing/eff-flow-broken-by-call.midica b/test/org/midica/testfiles/failing/eff-flow-broken-by-call.midica index b072989..e179352 100644 --- a/test/org/midica/testfiles/failing/eff-flow-broken-by-call.midica +++ b/test/org/midica/testfiles/failing/eff-flow-broken-by-call.midica @@ -1,9 +1,9 @@ INCLUDE inc/instruments.midica -0: vol.wait() +0: vol.wait().set(50) CALL func -0: .set(50) +0: .wait.set(50) FUNCTION func END \ No newline at end of file diff --git a/test/org/midica/testfiles/failing/eff-flow-broken-by-const.midica b/test/org/midica/testfiles/failing/eff-flow-broken-by-const.midica index 8454964..10c7023 100644 --- a/test/org/midica/testfiles/failing/eff-flow-broken-by-const.midica +++ b/test/org/midica/testfiles/failing/eff-flow-broken-by-const.midica @@ -1,7 +1,7 @@ INCLUDE inc/instruments.midica -0: vol.wait() +0: vol.wait().set(50) CONST $x = y -0: .set(50) +0: .wait.set(50) diff --git a/test/org/midica/testfiles/failing/eff-flow-broken-by-function.midica b/test/org/midica/testfiles/failing/eff-flow-broken-by-function.midica index 189b692..cf3094d 100644 --- a/test/org/midica/testfiles/failing/eff-flow-broken-by-function.midica +++ b/test/org/midica/testfiles/failing/eff-flow-broken-by-function.midica @@ -1,9 +1,9 @@ INCLUDE inc/instruments.midica -0: vol.wait() +0: vol.wait().set(50) FUNCTION func END -0: .set(50) +0: .wait.set(50) CALL func diff --git a/test/org/midica/testfiles/failing/eff-flow-broken-by-note.midica b/test/org/midica/testfiles/failing/eff-flow-broken-by-note.midica index 98b53db..3c9549c 100644 --- a/test/org/midica/testfiles/failing/eff-flow-broken-by-note.midica +++ b/test/org/midica/testfiles/failing/eff-flow-broken-by-note.midica @@ -1,7 +1,7 @@ INCLUDE inc/instruments.midica -0: vol.wait() +0: vol.wait().set(50) 0: c -0: .set(50) +0: .wait.set(50) diff --git a/test/org/midica/testfiles/failing/eff-flow-broken-by-other-channel.midica b/test/org/midica/testfiles/failing/eff-flow-broken-by-other-channel.midica index 9fab4ae..27f4223 100644 --- a/test/org/midica/testfiles/failing/eff-flow-broken-by-other-channel.midica +++ b/test/org/midica/testfiles/failing/eff-flow-broken-by-other-channel.midica @@ -1,7 +1,7 @@ INCLUDE inc/instruments.midica -0: vol.wait() -1: balance.wait() -0: .set(50) +0: vol.wait().set(50) +1: balance.wait().set(+50) +0: .wait.set(50) diff --git a/test/org/midica/testfiles/failing/eff-flow-broken-by-var.midica b/test/org/midica/testfiles/failing/eff-flow-broken-by-var.midica index b65d12a..b373c90 100644 --- a/test/org/midica/testfiles/failing/eff-flow-broken-by-var.midica +++ b/test/org/midica/testfiles/failing/eff-flow-broken-by-var.midica @@ -1,7 +1,7 @@ INCLUDE inc/instruments.midica -0: vol.double +0: vol.double.set(50) VAR $x = y -0: .set(50) +0: .wait.set(50) diff --git a/test/org/midica/testfiles/failing/eff-flow-pending-1.midica b/test/org/midica/testfiles/failing/eff-flow-pending-1.midica new file mode 100644 index 0000000..44f8906 --- /dev/null +++ b/test/org/midica/testfiles/failing/eff-flow-pending-1.midica @@ -0,0 +1,5 @@ +INCLUDE inc/instruments.midica + + +0: vol.wait +1: c diff --git a/test/org/midica/testfiles/failing/eff-flow-pending-2.midica b/test/org/midica/testfiles/failing/eff-flow-pending-2.midica new file mode 100644 index 0000000..a2b3981 --- /dev/null +++ b/test/org/midica/testfiles/failing/eff-flow-pending-2.midica @@ -0,0 +1,4 @@ +INCLUDE inc/instruments.midica + + +0: hold.wait \ No newline at end of file diff --git a/test/org/midica/testfiles/failing/eff-flow-pending-3.midica b/test/org/midica/testfiles/failing/eff-flow-pending-3.midica new file mode 100644 index 0000000..f9af5d0 --- /dev/null +++ b/test/org/midica/testfiles/failing/eff-flow-pending-3.midica @@ -0,0 +1,5 @@ +INCLUDE inc/instruments.midica + + +0: hold.wait + diff --git a/test/org/midica/testfiles/failing/eff-flow-pending-4.midica b/test/org/midica/testfiles/failing/eff-flow-pending-4.midica new file mode 100644 index 0000000..d6f45ad --- /dev/null +++ b/test/org/midica/testfiles/failing/eff-flow-pending-4.midica @@ -0,0 +1,24 @@ +INCLUDE inc/instruments.midica + + + +FUNCTION func + { + { + 0: hold.wait + + 0: c + + } + } +END + +{ + { + + CALL func + 0: a + + } +} +