private long indexToSample(Index index, int sampleRate) { // System.out.println(index.getPosition().getTotalFrames() / 75d * sampleRate); return (long) (index.getPosition().getTotalFrames() / 75d * sampleRate); } }
/** * Write a warning to the logging and the {@link jwbroek.cuelib.CueSheet} associated with the * {@link jwbroek.cuelib.LineOfInput}. * * @param input The {@link jwbroek.cuelib.LineOfInput} the warning pertains to. * @param warning The warning to write. */ private static void addWarning(final LineOfInput input, final String warning) { CueParser.logger.warning(warning); input.getAssociatedSheet().addWarning(input, warning); }
/** * Serialize the CueSheet. * * @param builder The StringBuilder to serialize to. * @param cueSheet The CueSheet to serialize. * @param indentation The current indentation. */ private void serializeCueSheet(final StringBuilder builder, final CueSheet cueSheet, final String indentation) { CueSheetSerializer.logger.entering (CueSheetSerializer.class.getCanonicalName() , "serializeCueSheet(StringBuilder,CueSheet,String)" , new Object[]{builder, cueSheet, indentation} ); CueSheetSerializer.logger.fine("Serializing cue sheet to cue format."); addField(builder, "REM GENRE", indentation, cueSheet.getGenre()); addField(builder, "REM DATE", indentation, cueSheet.getYear()); addField(builder, "REM DISCID", indentation, cueSheet.getDiscid()); addField(builder, "REM COMMENT", indentation, cueSheet.getComment()); addField(builder, "CATALOG", indentation, cueSheet.getCatalog()); addField(builder, "PERFORMER", indentation, cueSheet.getPerformer()); addField(builder, "TITLE", indentation, cueSheet.getTitle()); addField(builder, "SONGWRITER", indentation, cueSheet.getSongwriter()); addField(builder, "CDTEXTFILE", indentation, cueSheet.getCdTextFile()); for (FileData fileData : cueSheet.getFileData()) { serializeFileData(builder, fileData, indentation); } CueSheetSerializer.logger.exiting (CueSheetSerializer.class.getCanonicalName(), "serializeCueSheet(StringBuilder,CueSheet,String)"); }
/** * Parse the PREGAP command. * <p/> * PREGAP [mm:ss:ff] * Must come after TRACK, but before INDEX fields for that track. * * @param input */ private static void parsePregap(final LineOfInput input) { CueParser.logger.entering(CueParser.class.getCanonicalName(), "parsePregap(LineOfInput)", input); Matcher pregapMatcher = PATTERN_PREGAP.matcher(input.getInput()); if (startsWith(input, "PREGAP") && pregapMatcher.matches()) { TrackData trackData = getLastTrackData(input); if (trackData.getPregap() != null) { addWarning(input, WARNING_DATUM_APPEARS_TOO_OFTEN); } if (trackData.getIndices().size() > 0) { addWarning(input, WARNING_PREGAP_IN_WRONG_PLACE); } trackData.setPregap(parsePosition(input, pregapMatcher.group(1))); } else { addWarning(input, WARNING_UNPARSEABLE_INPUT); } CueParser.logger.exiting(CueParser.class.getCanonicalName(), "parsePregap(LineOfInput)"); }
/** * Serialize the FileData. * * @param builder The StringBuilder to serialize to. * @param fileData The FileData to serialize. * @param indentation The current indentation. */ private void serializeFileData(final StringBuilder builder, final FileData fileData, final String indentation) { CueSheetSerializer.logger.entering (CueSheetSerializer.class.getCanonicalName() , "serializeFileData(StringBuilder,FileData,String)" , new Object[]{builder, fileData, indentation} ); builder.append(indentation).append("FILE"); if (fileData.getFile() != null) { builder.append(' ').append(quoteIfNecessary(fileData.getFile())); } if (fileData.getFileType() != null) { builder.append(' ').append(quoteIfNecessary(fileData.getFileType())); } builder.append('\n'); for (TrackData trackData : fileData.getTrackData()) { serializeTrackData(builder, trackData, indentation + this.getIndentationValue()); } CueSheetSerializer.logger.exiting (CueSheetSerializer.class.getCanonicalName(), "serializeFileData(StringBuilder,FileData,String)"); }
/** * Parse the POSTGAP command. * <p/> * POSTGAP [mm:ss:ff] * Must come after all INDEX fields for a track. Only one per track allowed. * * @param input */ private static void parsePostgap(final LineOfInput input) { CueParser.logger.entering(CueParser.class.getCanonicalName(), "parsePostgap(LineOfInput)", input); Matcher postgapMatcher = PATTERN_POSTGAP.matcher(input.getInput()); if (startsWith(input, "POSTGAP") && postgapMatcher.matches()) { TrackData trackData = getLastTrackData(input); if (trackData.getPostgap() != null) { addWarning(input, WARNING_DATUM_APPEARS_TOO_OFTEN); } trackData.setPostgap(parsePosition(input, postgapMatcher.group(1))); } else { addWarning(input, WARNING_UNPARSEABLE_INPUT); } CueParser.logger.exiting(CueParser.class.getCanonicalName(), "parsePostgap(LineOfInput)"); }
/** * Parse the CDTEXTFILE command. * <p/> * CDTEXTFILE [filename] * File that contains cd text data. Not mandatory. * * @param input */ private static void parseCdTextFile(final LineOfInput input) { CueParser.logger.entering(CueParser.class.getCanonicalName(), "parseCdTextFile(LineOfInput)", input); Matcher cdTextFileMatcher = PATTERN_CDTEXTFILE.matcher(input.getInput()); if (startsWith(input, "CDTEXTFILE") && cdTextFileMatcher.matches()) { if (input.getAssociatedSheet().getCdTextFile() != null) { CueParser.logger.warning(WARNING_DATUM_APPEARS_TOO_OFTEN); input.getAssociatedSheet().addWarning(input, WARNING_DATUM_APPEARS_TOO_OFTEN); } // If the file name is enclosed in quotes, remove those. String file = cdTextFileMatcher.group(1); if (file.length() > 0 && file.charAt(0) == '"' && file.charAt(file.length() - 1) == '"') { file = file.substring(1, file.length() - 1); } input.getAssociatedSheet().setCdTextFile(file); } else { addWarning(input, WARNING_UNPARSEABLE_INPUT); } CueParser.logger.exiting(CueParser.class.getCanonicalName(), "parseCdTextFile(LineOfInput)"); }
/** * Parse the CATALOG command. * <p/> * CATALOG [media-catalog-number] * CD catalog number. Code follows UPC/EAN rules. * Usually the first command, but this is not required. Not a mandatory command. * * @param input */ private static void parseCatalog(final LineOfInput input) { CueParser.logger.entering(CueParser.class.getCanonicalName(), "parseCatalog(LineOfInput)", input); if (startsWith(input, "CATALOG")) { String catalogNumber = input.getInput().substring("CATALOG".length()).trim(); if (!PATTERN_CATALOG_NUMBER.matcher(catalogNumber).matches()) { addWarning(input, WARNING_INVALID_CATALOG_NUMBER); } if (input.getAssociatedSheet().getCatalog() != null) { addWarning(input, WARNING_DATUM_APPEARS_TOO_OFTEN); } input.getAssociatedSheet().setCatalog(catalogNumber); } else { addWarning(input, WARNING_UNPARSEABLE_INPUT); } CueParser.logger.exiting(CueParser.class.getCanonicalName(), "parseCatalog(LineOfInput)"); }
/** * Get the last {@link jwbroek.cuelib.FileData} element. If none exist, an empty one is created and a warning * added. * * @param input * @return The last {@link jwbroek.cuelib.FileData} element. If none exist, an empty one is created and a warning * added. */ private static FileData getLastFileData(final LineOfInput input) { CueParser.logger.entering(CueParser.class.getCanonicalName(), "getLastFileData(LineOfInput)", input); List<FileData> fileDataList = input.getAssociatedSheet().getFileData(); if (fileDataList.size() == 0) { fileDataList.add(new FileData(input.getAssociatedSheet())); addWarning(input, WARNING_NO_FILE_SPECIFIED); } FileData result = fileDataList.get(fileDataList.size() - 1); CueParser.logger.exiting(CueParser.class.getCanonicalName(), "getLastFileData(LineOfInput)", result); return result; }
/** * Serialize the index. * @param parentElement The parent element for the TrackData. * @param index The Index to serialize. */ private void serializeIndex(final Element parentElement, final Index index) { CueSheetToXmlSerializer.logger.entering ( CueSheetToXmlSerializer.class.getCanonicalName() , "serializeIndex(Element,Index)" , new Object[] {parentElement, index} ); Element indexElement = addElement(parentElement, "index", index.getPosition(), true); addAttribute(indexElement, "number", index.getNumber()); CueSheetToXmlSerializer.logger.exiting (CueSheetToXmlSerializer.class.getCanonicalName(), "serializeIndex(Element,Index)"); }
/** * Get the last {@link jwbroek.cuelib.TrackData} element. If none exist, an empty one is created and a warning * added. * * @param input * @return The last {@link jwbroek.cuelib.TrackData} element. If none exist, an empty one is created and a * warning added. */ private static TrackData getLastTrackData(final LineOfInput input) { CueParser.logger.entering(CueParser.class.getCanonicalName(), "getLastTrackData(LineOfInput)", input); FileData lastFileData = getLastFileData(input); List<TrackData> trackDataList = lastFileData.getTrackData(); if (trackDataList.size() == 0) { trackDataList.add(new TrackData(lastFileData)); addWarning(input, WARNING_NO_TRACK_SPECIFIED); } TrackData result = trackDataList.get(trackDataList.size() - 1); CueParser.logger.exiting(CueParser.class.getCanonicalName(), "getLastTrackData(LineOfInput)", result); return result; }
/** * Parse the non-standard REM DATE command. * <p/> * REM DATE [year] * * @param input */ private static void parseRemDate(final LineOfInput input) { CueParser.logger.entering(CueParser.class.getCanonicalName(), "parseRemDate(LineOfInput)", input); Matcher matcher = PATTERN_REM_DATE.matcher(input.getInput()); if (matcher.find()) { int year = Integer.parseInt(matcher.group(2)); if (year < 1 || year > 9999) { addWarning(input, WARNING_INVALID_YEAR); } input.getAssociatedSheet().setYear(year); } else { addWarning(input, WARNING_UNPARSEABLE_INPUT); } CueParser.logger.exiting(CueParser.class.getCanonicalName(), "parseRemDate(LineOfInput)"); }
/** * Parse the non-standard REM GENRE command. * <p/> * REM GENRE [genre] * * @param input */ private static void parseRemGenre(final LineOfInput input) { CueParser.logger.entering(CueParser.class.getCanonicalName(), "parseRemGenre(LineOfInput)", input); Matcher matcher = PATTERN_REM_GENRE.matcher(input.getInput()); if (matcher.find()) { String genre = matcher.group(2); if (genre.charAt(0) == '"' && genre.charAt(genre.length() - 1) == '"') { genre = genre.substring(1, genre.length() - 1); } input.getAssociatedSheet().setGenre(genre); } else { addWarning(input, WARNING_UNPARSEABLE_INPUT); } CueParser.logger.exiting(CueParser.class.getCanonicalName(), "parseRemGenre(LineOfInput)"); }
/** * Parse the non-standard REM COMMENT command. * <p/> * REM COMMENT [comment] * * @param input */ private static void parseRemComment(final LineOfInput input) { CueParser.logger.entering(CueParser.class.getCanonicalName(), "parseRemComment(LineOfInput)", input); Matcher matcher = PATTERN_REM_COMMENT.matcher(input.getInput()); if (matcher.find()) { String comment = matcher.group(2); if (comment.charAt(0) == '"' && comment.charAt(comment.length() - 1) == '"') { comment = comment.substring(1, comment.length() - 1); } input.getAssociatedSheet().setComment(comment); } else { addWarning(input, WARNING_UNPARSEABLE_INPUT); } CueParser.logger.exiting(CueParser.class.getCanonicalName(), "parseRemComment(LineOfInput)"); }
/** * Parse the non-standard REM DISCID command. * <p/> * REM DISCID [discid] * * @param input */ private static void parseRemDiscid(final LineOfInput input) { CueParser.logger.entering(CueParser.class.getCanonicalName(), "parseRemDiscid(LineOfInput)", input); Matcher matcher = PATTERN_REM_DISCID.matcher(input.getInput()); if (matcher.find()) { String discid = matcher.group(2); if (discid.charAt(0) == '"' && discid.charAt(discid.length() - 1) == '"') { discid = discid.substring(1, discid.length() - 1); } input.getAssociatedSheet().setDiscid(discid); } else { addWarning(input, WARNING_UNPARSEABLE_INPUT); } CueParser.logger.exiting(CueParser.class.getCanonicalName(), "parseRemDiscid(LineOfInput)"); }
/** * Serialize the index. * * @param builder The StringBuilder to serialize to. * @param index The Index to serialize. * @param indentation The current indentation. */ private void serializeIndex(final StringBuilder builder, final Index index, final String indentation) { CueSheetSerializer.logger.entering (CueSheetSerializer.class.getCanonicalName() , "serializeIndex(StringBuilder,Index,String)" , new Object[]{builder, index, indentation} ); builder.append(indentation).append("INDEX"); if (index.getNumber() > -1) { builder.append(' ').append(String.format("%1$02d", index.getNumber())); } if (index.getPosition() != null) { builder.append(' ').append(formatPosition(index.getPosition())); } builder.append('\n'); CueSheetSerializer.logger.exiting (CueSheetSerializer.class.getCanonicalName(), "serializeIndex(StringBuilder,Index,String)"); }
/** * Format the specified position. * * @param position * @return The formatted position. */ private String formatPosition(final Position position) { CueSheetSerializer.logger.entering(CueSheetSerializer.class.getCanonicalName(), "formatPosition(Position)", position); String result = String.format ("%1$02d:%2$02d:%3$02d", position.getMinutes(), position.getSeconds(), position.getFrames()); CueSheetSerializer.logger.exiting(CueSheetSerializer.class.getCanonicalName(), "formatPosition(Position)", result); return result; }
/** * Determine if the input starts with some string. Will return true if it matches, regardless of case. If there is * a match, but the case differs, then a "TOKEN NOT UPPERCASE" warning will be added to the cue sheet associated * with the input. * * @param input The input to check. * @param start The starting string to check for. Should be uppercase, or else the warning will not make sense. * @return True if there is a match. False otherwise. */ private static boolean startsWith(final LineOfInput input, final String start) { CueParser.logger.entering (CueParser.class.getCanonicalName(), "startsWith(LineOfInput,String)", new Object[]{input, start}); if (input.getInput().startsWith(start)) { CueParser.logger.exiting(CueParser.class.getCanonicalName(), "startsWith(LineOfInput,String)", true); return true; } else if (input.getInput().substring(0, start.length()).equalsIgnoreCase(start)) { addWarning(input, WARNING_TOKEN_NOT_UPPERCASE); CueParser.logger.exiting(CueParser.class.getCanonicalName(), "startsWith(LineOfInput,String)", true); return true; } else { CueParser.logger.exiting(CueParser.class.getCanonicalName(), "startsWith(LineOfInput,String)", false); return false; } }
/** * Add an error message to this cue sheet. * @param lineOfInput The line of input that caused the error. * @param message A message describing the error. */ public void addError(LineOfInput lineOfInput, String message) { logger.entering (CueSheet.class.getCanonicalName(), "addError(LineOfInput,String)", new Object[]{lineOfInput, message}); this.messages.add(new Error(lineOfInput, message)); logger.exiting(CueSheet.class.getCanonicalName(), "addError(LineOfInput,String)"); }
/** * Add a warning message to this cue sheet. * @param lineOfInput The line of input that caused the warning. * @param message A message describing the warning. */ public void addWarning(LineOfInput lineOfInput, String message) { logger.entering (CueSheet.class.getCanonicalName(), "addWarning(LineOfInput,String)", new Object[]{lineOfInput, message}); this.messages.add(new Warning(lineOfInput, message)); logger.exiting(CueSheet.class.getCanonicalName(), "addWarning(LineOfInput,String)"); }