/** * Parses the ABCHeader information as prescribed by the ABC Grammar subset understood by the * ABCParser */ private void parseHeader() { // All the components of a valid ABCMusic List<Voice> VoicesList = new ArrayList<Voice>(); String name, title, IDNum; int bpm; int[] meterSum = new int[2]; int[] noteLength = new int[2]; NoteToken key; // Booleans for having set the optional quantities boolean setL = Boolean.FALSE; boolean setM = Boolean.FALSE; boolean setQ = Boolean.FALSE; boolean setC = Boolean.FALSE; // Establish Defaults for unnecessary fields so that we only need to add // the the vars bpm = 100; noteLength[0] = 1; noteLength[1] = 8; meterSum[0] = 4; meterSum[1] = 4; name = "Unknown"; // Now grab X and T since they are in a manditory order IDNum = lexer.getNextElemToken().getText(); checkAndTrashEoL(); next = lexer.GetNextTokenType(); if (next == Tokens.Type.FIELD_TITLE) { title = lexer.getNextElemToken().getText(); } else { throw new IllegalArgumentException("Expected a music Title, received: " + next); } checkAndTrashEoL(); // Until you encounter the Field Key, look for all optional classes, and only allow them to be // set once while (next != Tokens.Type.FIELD_KEY) { next = lexer.GetNextTokenType(); switch (next) { case FIELD_DEFAULT_LENGTH: if (!setL) { ElemToken tempToken = lexer.getNextElemToken(); int[] settingArray = tempToken.getVals(); noteLength[0] = settingArray[0]; noteLength[1] = settingArray[1]; setL = Boolean.TRUE; } else { throw new IllegalArgumentException("Cannot Set Default Length more than once"); } checkAndTrashEoL(); break; case FIELD_METER: if (!setM) { ElemToken tempToken = lexer.getNextElemToken(); int[] settingArray = tempToken.getVals(); meterSum[0] = settingArray[0]; meterSum[1] = settingArray[1]; setM = Boolean.TRUE; } else { throw new IllegalArgumentException("Cannot Set Meter Length more than once"); } checkAndTrashEoL(); break; case FIELD_TEMPO: if (!setQ) { ElemToken tempToken = lexer.getNextElemToken(); int[] settingArray = tempToken.getVals(); bpm = settingArray[0]; setQ = Boolean.TRUE; } else { throw new IllegalArgumentException("Cannot Set Tempo more than once"); } checkAndTrashEoL(); break; case FIELD_COMPOSER: if (!setC) { ElemToken tempToken = lexer.getNextElemToken(); name = tempToken.getText(); setC = Boolean.TRUE; } else { throw new IllegalArgumentException("Cannot Set Composer more than once"); } checkAndTrashEoL(); break; case FIELD_VOICE: VoicesList.add(new Voice(lexer.getNextElemToken().getText())); checkAndTrashEoL(); break; default: break; } } // Last element should be the field key if (next == Tokens.Type.FIELD_KEY) { key = lexer.getNextElemToken().getKey(); } else { throw new IllegalArgumentException("Expected a music Key for the piece, received: " + next); } checkAndTrashEoL(); // If the file has no voices, then we need at least one for the ABCMusic file to be valid // Construct a dummy one if (VoicesList.size() == 0) { VoicesList.add(new Voice("DummyVoice")); } // Initialize the new ABCMusic file ThePiece = new ABCMusic(VoicesList, name, key, noteLength, meterSum, bpm, title, IDNum); }
/** * Parses a given set of Meters in a given Voice until an EoL character is found utilizes a list * of mutable, working meters to manage repeats * * <p>Note: Highly dependent on proper use of copying references to a list versus copying the * actual list so edit carefully * * <p>Note: Assumes that nested repeats do not exist, however they are musically unsound so the * assumption seems valid */ private void parseBar() { Bars workingBar; // If we havent used the voice, initialie its repeatList, else get its repeat list if (repeatTracker.size() < (workingIndex + 1)) { workingBar = new Bars(); repeatTracker.add(workingBar); } else { workingBar = repeatTracker.get(workingIndex); } // Construct our working meter and recursively get it Meters workingMeter; while (next != Tokens.Type.END_OF_LINE && next != Tokens.Type.COMMENT) { workingMeter = parseMeter(); workingBar.addElts(workingMeter); next = lexer.GetNextTokenType(); // If we find an end of meter if (next == Tokens.Type.BARLINE) { ElemToken barToken = lexer.getNextElemToken(); switch (barToken.getVals()[0]) { case 1: // Do nothing for regular meters break; case 3: // Add all marked for repeat meters to the voice for repeats workingVoice.addCopyElts(workingBar); break; default: // Add all unadded meters and clear what gets repeated otherwise workingVoice.addCopyElts(workingBar); workingBar.clear(); break; } next = lexer.GetNextTokenType(); // If we find a # Repeat token } else if (next == Tokens.Type.REPEAT) { int repeatNum = lexer.getNextElemToken().getVals()[0]; // Only for the first repeat token if (repeatNum == 1) { // Temporarily store the contents to be repeated Bars tempBar = new Bars(); for (Iterator<Meters> i = workingBar.MetersList.iterator(); i.hasNext(); ) { tempBar.addCopyElts(i.next()); } // Recursively parse to the Repeat Barline char, which will add the meters // Then clear the list and re-add everything we stored before getting the // First repeat information parseBar(); workingBar.clear(); for (Iterator<Meters> i = tempBar.MetersList.iterator(); i.hasNext(); ) { workingBar.addCopyElts(i.next()); } // Now get the second repeat information parseBar(); } else { // Just break the given nested parse for second repeats, they are // handled by Barline characters that end them break; } next = lexer.GetNextTokenType(); } else if (next == Tokens.Type.END_OF_LINE || next == Tokens.Type.COMMENT) { break; } else { throw new IllegalArgumentException("Expected a bar to have a termination, got: " + next); } } }