com.rockhoppertech.music.DurationParser.java Source code

Java tutorial

Introduction

Here is the source code for com.rockhoppertech.music.DurationParser.java

Source

package com.rockhoppertech.music;

/*
 * #%L
 * Rocky Music Core
 * %%
 * Copyright (C) 1996 - 2013 Rockhopper Technologies
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.ImmutableMap;
import com.rockhoppertech.music.series.time.TimeSeries;

/**
 * @author <a href="mailto:gene@rockhoppertech.com">Gene De Lisa</a>
 * 
 */
public class DurationParser {

    static Logger logger = LoggerFactory.getLogger(DurationParser.class);

    // or using google collections
    public static final ImmutableMap<String, Double> DMAP = new ImmutableMap.Builder<String, Double>()
            .put("d", Duration.DOUBLE_WHOLE_NOTE).put("w", Duration.WHOLE_NOTE).put("h", Duration.HALF_NOTE)
            .put("q", Duration.QUARTER_NOTE).put("e", Duration.EIGHTH_NOTE).put("s", Duration.SIXTEENTH_NOTE)
            .put("t", Duration.THIRTY_SECOND_NOTE).put("x", Duration.SIXTY_FOURTH_NOTE)
            .put("o", Duration.ONE_TWENTY_EIGHTH_NOTE).build();

    private static Map<String, Double> durKeyMap;

    // not dotted
    static Pattern pattern = Pattern.compile("[dwhqestxo]+[^\\.]*");
    // it is dotted
    static Pattern dpattern = Pattern.compile("[dwhqestxo]+\\.+");
    // static Pattern tripletPattern = Pattern.compile("[dwhqestxo]+t+");

    static {
        useDefaultDurationMap();

    }

    public static void useDefaultDurationMap() {
        durKeyMap = new LinkedHashMap<String, Double>();
        durKeyMap.put("dt", Duration.DOUBLE_WHOLE_TRIPLET_NOTE);
        durKeyMap.put("d", Duration.DOUBLE_WHOLE_NOTE);
        durKeyMap.put("wt", Duration.WHOLE_TRIPLET_NOTE);
        durKeyMap.put("w", Duration.WHOLE_NOTE);
        durKeyMap.put("ht", Duration.HALF_TRIPLET_NOTE);
        durKeyMap.put("h", Duration.HALF_NOTE);
        durKeyMap.put("qt", Duration.QUARTER_TRIPLET_NOTE);
        durKeyMap.put("q", Duration.QUARTER_NOTE);
        durKeyMap.put("et", Duration.EIGHTH_TRIPLET_NOTE);
        durKeyMap.put("e", Duration.EIGHTH_NOTE);
        durKeyMap.put("st", Duration.SIXTEENTH_TRIPLET_NOTE);
        durKeyMap.put("s", Duration.SIXTEENTH_NOTE);
        durKeyMap.put("tt", Duration.THIRTY_SECOND_TRIPLET_NOTE);
        durKeyMap.put("t", Duration.THIRTY_SECOND_NOTE);
        durKeyMap.put("xt", Duration.SIXTY_FOURTH_TRIPLET_NOTE);
        durKeyMap.put("x", Duration.SIXTY_FOURTH_NOTE);
        durKeyMap.put("ot", Duration.ONE_TWENTY_EIGHTH_TRIPLET_NOTE);
        durKeyMap.put("o", Duration.ONE_TWENTY_EIGHTH_NOTE);
    }

    public static void multiplyDurationMapByFactor(double factor) {
        durKeyMap = new LinkedHashMap<String, Double>();
        durKeyMap.put("dt", Duration.DOUBLE_WHOLE_TRIPLET_NOTE * factor);
        durKeyMap.put("d", Duration.DOUBLE_WHOLE_NOTE * factor);
        durKeyMap.put("wt", Duration.WHOLE_TRIPLET_NOTE * factor);
        durKeyMap.put("w", Duration.WHOLE_NOTE * factor);
        durKeyMap.put("ht", Duration.HALF_TRIPLET_NOTE * factor);
        durKeyMap.put("h", Duration.HALF_NOTE * factor);
        durKeyMap.put("qt", Duration.QUARTER_TRIPLET_NOTE * factor);
        durKeyMap.put("q", Duration.QUARTER_NOTE * factor);
        durKeyMap.put("et", Duration.EIGHTH_TRIPLET_NOTE * factor);
        durKeyMap.put("e", Duration.EIGHTH_NOTE * factor);
        durKeyMap.put("st", Duration.SIXTEENTH_TRIPLET_NOTE * factor);
        durKeyMap.put("s", Duration.SIXTEENTH_NOTE * factor);
        durKeyMap.put("tt", Duration.THIRTY_SECOND_TRIPLET_NOTE * factor);
        durKeyMap.put("t", Duration.THIRTY_SECOND_NOTE * factor);
        durKeyMap.put("xt", Duration.SIXTY_FOURTH_TRIPLET_NOTE * factor);
        durKeyMap.put("x", Duration.SIXTY_FOURTH_NOTE * factor);
        durKeyMap.put("ot", Duration.ONE_TWENTY_EIGHTH_TRIPLET_NOTE * factor);
        durKeyMap.put("o", Duration.ONE_TWENTY_EIGHTH_NOTE * factor);
    }

    public static final Pattern allPattern = Pattern.compile("\\s*[dwhqestxo]+t*\\.*");

    public static boolean couldBeDurationString(String s) {
        // return allPattern.matcher(s).matches();
        return allPattern.matcher(s).find();
    }

    public static double getDuration(String durationString) {
        // is it dotted?
        // Pattern dot = Pattern.compile("\\.+");
        if (dpattern.matcher(durationString).matches()) {
            // Matcher m = dpattern.matcher(durationString);
            // String token = durationString.substring(m.start(),
            // m.end());
            return getDottedValue(durationString);
        }
        return durKeyMap.get(durationString);
    }

    public static void print() {
        for (String key : durKeyMap.keySet()) {
            System.out.println(String.format("%s = %f", key, durKeyMap.get(key)));

            key += ".";
            System.out.println(String.format("%s = %f", key, getDuration(key)));

            key += ".";
            System.out.println(String.format("%s = %f", key, getDuration(key)));
        }
    }

    /**
     * Parse a duration string into a {@code TimeSeries}.
     * 
     * <pre>
     * {@code
    * String both = "1 2 3 q q. e .5 a q.. q...";
    * TimeSeries ts = DurationParser.getDurationAsTimeSeries(both);
    * }
    * </pre>
     * 
     * @param s
     *            a duration string
     * @return a new {@code TimeSeries}
     */
    public static TimeSeries getDurationAsTimeSeries(String s) {
        TimeSeries ts = new TimeSeries();
        return getDurationAsTimeSeries(ts, s);
    }

    /**
     * Copies new events into the TimeSeries parameter - which is also returned.
     * 
     * @param ts
     *            a {@code TimeSeries} that will be added to
     * @param s
     *            a duration string
     * @return the same{@code TimeSeries} that you passed in
     */
    public static TimeSeries getDurationAsTimeSeries(TimeSeries ts, String s) {
        String token = null;
        Scanner scanner = new Scanner(s);

        if (s.indexOf(',') != -1) {
            scanner.useDelimiter(",");
        }

        while (scanner.hasNext()) {
            if (scanner.hasNext(dpattern)) {
                token = scanner.next(dpattern);
                double d = getDottedValue(token);
                ts.add(d);
                logger.debug("'{}' is dotted value is {}", token, d);

            } else if (scanner.hasNext(pattern)) {
                token = scanner.next(pattern);
                double d = durKeyMap.get(token);
                ts.add(d);
                logger.debug("'{}' is not dotted value is {}", token, d);
                // } else if (scanner.hasNext(tripletPattern)) {
                // token = scanner.next(tripletPattern);
                // double d = durKeyMap.get(token);
                // ts.add(d);
                // System.out.println(String
                // .format("'%s' is not dotted value is %f",
                // token,
                // d));
            } else if (scanner.hasNextDouble()) {
                double d = scanner.nextDouble();
                ts.add(d);
                logger.debug("{} is a double", d);
            } else {
                // just ignore it. or throw exception?
                String skipped = scanner.next();
                logger.debug("skipped '{}'", skipped);
            }
        }
        scanner.close();
        return ts;
    }

    private static double getDottedValue(String token) {
        String s = token.substring(0, token.indexOf('.'));
        double val = durKeyMap.get(s);
        int dots = StringUtils.countMatches(token, ".");
        val = Duration.getDotted(val, dots);
        return val;
    }

    private static String getKeyString(double duration) {
        for (Entry<String, Double> e : durKeyMap.entrySet()) {
            if (Math.abs(duration - e.getValue()) < .0000001) {
                // if (e.getValue() == duration) {
                return e.getKey();
            }
        }
        return null;
    }

    private static String getNearestKeyString(double duration) {
        double dotted = Duration.getDotted(duration, 1);
        String key = null;
        // String p = null;
        for (Entry<String, Double> e : durKeyMap.entrySet()) {
            if (e.getValue() >= (dotted - duration)) {
                key = e.getKey();
            } else {
            }
        }
        return key;
    }

    // public static String getDurationString(TimeSeries series) {
    // StringBuilder sb = new StringBuilder();
    // for (Timed t : series) {
    // double d = t.getDuration();
    // if (durKeyMap.containsValue(d)) {
    // sb.append(getKeyString(d)).append(' ');
    // System.err.printf("contains value %s %f\n", sb, d);
    // continue;
    // }
    //
    // String nearest = getNearestKeyString(d);
    // double nearestDuration = durKeyMap.get(nearest);
    // System.err.printf("%fs nearest value %s nd %f\n", d, nearest,
    // nearestDuration);
    //
    // boolean foundDotted = false;
    // for (int i = 1; i < 3; i++) {
    // double dotted = Duration.getDotted(nearestDuration, i);
    // System.err.printf("dotted %d %f = %f?\n", i, dotted, d);
    // if (d == dotted) {
    // foundDotted = true;
    // sb.append(nearest);
    // for (int j = 0; j < i; j++) {
    // sb.append('.');
    // }
    // sb.append(' ');
    // }
    // }
    //
    // // not in the map and not dotted, just give the value
    // if (foundDotted == false) {
    // sb.append(d).append(' ');
    // }
    //
    // }
    // return sb.toString();
    //
    // }

    // public static String getDurationString(TimeSeries series) {
    // StringBuilder sb = new StringBuilder();
    // for (Timed t : series) {
    // double d = t.getDuration();
    // sb.append(getDurationString(d)).append(' ');
    // }
    // return sb.toString().trim();
    // }

    public static String getDurationString(double d) {
        StringBuilder sb = new StringBuilder();
        boolean foundInMap = false;
        if (durKeyMap.containsValue(d)) {
            sb.append(getKeyString(d)).append(' ');
            // System.err.printf("contains value %s %f\n", sb, d);
            foundInMap = true;
        }

        String nearest = getNearestKeyString(d);
        double nearestDuration = durKeyMap.get(nearest);
        // System.err.printf("%fs nearest value %s nd %f\n", d, nearest,
        // nearestDuration);

        boolean foundDotted = false;
        for (int i = 1; i < 3; i++) {
            double dotted = Duration.getDotted(nearestDuration, i);
            // System.err.printf("dotted %d %f = %f?\n", i, dotted, d);
            // if (d == dotted) {
            if (Math.abs(d - dotted) < .0000001) {

                foundDotted = true;
                sb.append(nearest);
                for (int j = 0; j < i; j++) {
                    sb.append('.');
                }
                sb.append(' ');
            }
        }

        // not in the map and not dotted, just give the value
        if (foundDotted == false && foundInMap == false) {
            sb.append(d).append(' ');
        }

        return sb.toString().trim();

    }

    /**
     * @param args
     *            cmd line arguments
     */
    public static void main(String[] args) {
        DurationParser.print();

        // String both = "h h. h.. h... h.... q q. q..";
        // String both = "1 2 3 q q. e .5 a q.. q...";
        // TimeSeries ts = DurationParser.getDurationAsTimeSeries(both);
        // System.err.println(ts);
        //
        // ts = DurationParser.getDurationAsTimeSeries("q q q q");
        // System.err.println(DurationParser.getDurationString(ts));

        // TimeSeries ts = DurationParser
        // .getDurationAsTimeSeries("q q. q.. e e. w w. 1.321");
        // System.err.println(DurationParser.getDurationString(ts));

        System.err.println();
        String s = null;
        double d = .5;
        s = DurationParser.getDurationString(d);
        System.err.println(String.format("'%s' for %f", s, d));

        s = DurationParser.getDurationString(d = 1.0);
        System.err.println(String.format("'%s' for %f", s, d));

        s = DurationParser.getDurationString(d = 1.5);
        System.err.println(String.format("'%s' for %f", s, d));

        s = DurationParser.getDurationString(d = 1.321);
        System.err.println(String.format("'%s' for %f", s, d));

        s = DurationParser.getDurationString(d = 2.0);
        System.err.println(String.format("'%s' for %f", s, d));

        s = DurationParser.getDurationString(d = 3.0);
        System.err.println(String.format("'%s' for %f", s, d));

        s = DurationParser.getDurationString(d = 3.5);
        System.err.println(String.format("'%s' for %f", s, d));

        s = DurationParser.getDurationString(d = 4.0);
        System.err.println(String.format("'%s' for %f", s, d));

        // q q. q.. e e. w w. 1.321

    }

    /**
     * @return the durKeyMap
     */
    public static Map<String, Double> getDurKeyMap() {
        return Collections.unmodifiableMap(durKeyMap);
    }

    /**
     * @param durKeyMap
     *            the durKeyMap to set
     */
    public static void setDurKeyMap(Map<String, Double> durKeyMap) {
        DurationParser.durKeyMap = durKeyMap;
    }

    public static List<Double> getDurationsAsList(String durations) {
        String token = null;
        List<Double> list = new ArrayList<Double>();
        Scanner scanner = new Scanner(durations);

        if (durations.indexOf(',') != -1) {
            scanner.useDelimiter(",");
        }

        while (scanner.hasNext()) {
            if (scanner.hasNext(dpattern)) {
                token = scanner.next(dpattern);
                double d = getDottedValue(token);
                list.add(d);
                logger.debug("'{}' is dotted value is {}", token, d);

            } else if (scanner.hasNext(pattern)) {
                token = scanner.next(pattern);
                double d = durKeyMap.get(token);
                list.add(d);
                logger.debug("'{}' is not dotted value is {}", token, d);
                // } else if (scanner.hasNext(tripletPattern)) {
                // token = scanner.next(tripletPattern);
                // double d = durKeyMap.get(token);
                // ts.add(d);
                // System.out.println(String
                // .format("'%s' is not dotted value is %f",
                // token,
                // d));
            } else if (scanner.hasNextDouble()) {
                double d = scanner.nextDouble();
                list.add(d);
                logger.debug("{} is a double", d);
            } else {
                // just ignore it. or throw exception?
                String skipped = scanner.next();
                logger.debug("skipped '{}'", skipped);
            }
        }
        scanner.close();
        return list;
    }

}