@Test public void sanityCheck4() { String input = "X: 1\nT:Piece No.1\nM:4/4\nL:1/4\nQ: 140\nK:C\nC C C3/4 D/4 E | E3/4 D/4 E3/4 F/4 G2 | (3c/c/c/ (3G/G/G/ (3E/E/E/ (3C/C/C/ | G3/4 F/4 E3/4 D/4 C2 |]"; ABCLexer lexer = new ABCLexer(input); ABCParser parser = new ABCParser(lexer); ABCMusic music = parser.parse(); System.out.println(music.toString()); }
@Test // Sanity check to make sure the header is parsed correctly public void sanityCheck1() { String input = "X:1\nT:Paddy O'Rafferty\nC:Trad.\nM:6/8\nQ:200\nK:D\naaaaaa|]"; ABCLexer lexer = new ABCLexer(input); ABCParser parser = new ABCParser(lexer); ABCMusic music = parser.parse(); music.DisplayInfo(); }
@Test // Sanity check to make sure the header is parsed correctly public void sanityCheck2() { String input = "X:8628\nT:Prelude BWV 846 no. 1\nC:Johann Sebastian Bach\nM:4/4\nL:1/16\nQ:280\nV:1\nK:C\nV:1\nz2 Gc eGce z2 Gc eGce|]"; ABCLexer lexer = new ABCLexer(input); ABCParser parser = new ABCParser(lexer); ABCMusic music = parser.parse(); music.DisplayInfo(); }
@Test // Sanity check on a short piece of music to enusre it is handling the notes correctly // Since the output from the toString method is different from input abc format, but only // slightly, it is easier to leave this test // as a visual check rather than an assertEquals public void sanityCheck3() { String input = "X:1\nT:Simple scale\nC:Unknown\nM:4/4\nL:1/4\nQ:120\nK:C\nC D E F | G A B c | c B A G | F E D C |"; ABCLexer lexer = new ABCLexer(input); ABCParser parser = new ABCParser(lexer); ABCMusic music = parser.parse(); System.out.println(music.toString()); }
/** * The terminal recursion method that compiles the list of NoteTokens that make up a given meter * according to the ABC Grammar specifications * * <p>Note: Currently only enforces that a meter not have timing greater than specified in the * ABCHeader but does not care about truncated Meters, apparently those are okay in music * * <p>Note: Assumes that meters can be of any length if desired, even if those lengths violate the * M field this is due to the availability of truncated starts and ends, or switches to time mid * music * * @return An ADT Meters that contains a list of all the NoteTokens that exist in the meter it * begins from */ private Meters parseMeter() { next = lexer.GetNextTokenType(); Meters currentMeter = new Meters(); // Create variables to enforce meter lengths double noteLength; double meterCount = 0; double meterLength = ((double) ThePiece.getMeterSum()[0]) / ((double) ThePiece.getMeterSum()[1]); // Until the given meter is terminated while (next != Tokens.Type.BARLINE && next != Tokens.Type.REPEAT && next != Tokens.Type.END_OF_LINE && next != Tokens.Type.COMMENT && meterCount < meterLength) { NoteToken nextToken = lexer.getNextNoteToken(); switch (next) { case NOTE: case REST: // Construct the note or rest length and add it to the meter length noteLength = (((double) (nextToken.getLength()[0] * ThePiece.getNoteLength()[0])) / ((double) (nextToken.getLength()[1] * (double) ThePiece.getNoteLength()[1]))); meterCount += noteLength; // As long as the meter is not overloaded, add the note or rest to the Meters List if (meterCount <= meterLength) { currentMeter.addElts(nextToken); next = lexer.GetNextTokenType(); } else { throw new IllegalArgumentException( "Overloaded Meter with count greater than permitted"); } next = lexer.GetNextTokenType(); break; case TUPLET: // Calculate the Tuplet length as a product of the type of Tuplet and its inner note // lengths // this is dependent on all Tuplet notes having the same length noteLength = (((double) (nextToken.getElts()[0].getLength()[0] * ThePiece.getNoteLength()[0])) / ((double) (nextToken.getElts()[0].getLength()[1] * (double) ThePiece.getNoteLength()[1]))); noteLength = noteLength * nextToken.getLength()[0]; meterCount += noteLength; // Add each note in the Tuplet as long as the whole tuplet would fit in the meter if (meterCount <= meterLength) { for (int i = 0; i < nextToken.getElts().length; i++) { currentMeter.addElts( nextToken.getElts()[i].changeLength( nextToken.getLength()[0], nextToken.getLength()[1])); } next = lexer.GetNextTokenType(); } else { throw new IllegalArgumentException( "Overloaded Meter with a tuplet, is it counted wrong?"); } next = lexer.GetNextTokenType(); break; case CHORD: // A Chord is multiple notes played at once, so its length is simply the length of one of // the elements // This relies on the Chord having all notes of the same length noteLength = (((double) (nextToken.getLength()[0] * ThePiece.getNoteLength()[0])) / ((double) (nextToken.getLength()[1] * (double) ThePiece.getNoteLength()[1]))); meterCount += noteLength; // If the Chord fits, add its construct to the Meters List if (meterCount <= meterLength) { currentMeter.addElts(nextToken); next = lexer.GetNextTokenType(); } else { throw new IllegalArgumentException( "Overloaded Meter with a tuplet, is it counted wrong?"); } next = lexer.GetNextTokenType(); break; default: throw new IllegalArgumentException( "Somehow made a note token, but it was not a NOTE, TUPLET, CHORD or REST"); } } // To check measure lengths vs meter, apparently this no longer matters, kept for legacy /* System.out.println(meterCount+" vs "+meterLength); if(meterCount != meterLength && meterCount + .000001 < meterLength){ throw new IllegalArgumentException("Got a meter with the wrong timing, bad stuff mang"); } */ // Return the finished meter return currentMeter; }