package com.xenoage.zong.core.music.time; import static com.xenoage.utils.math.Fraction.fr; import lombok.Data; import com.xenoage.utils.annotations.Const; import com.xenoage.utils.math.Fraction; /** * Type of a time signature, e.g. a 4/4, alla breve or senza misura time. * * This class includes some common instances which may be reused. * * A senza-misura element time indicates that there is no time signature. * Thus as many beats as needed are allowed for each measure. * * @author Andreas Wenger */ @Const @Data public final class TimeType { /** 2/2 time. */ public static final TimeType time_2_2 = new TimeType(2, 2, TimeSymbol.Fractional, new boolean[]{true, false}); /** 2/4 time. */ public static final TimeType time_2_4 = new TimeType(2, 4, TimeSymbol.Fractional, new boolean[]{true, false}); /** 3/4 time. */ public static final TimeType time_3_4 = new TimeType(3, 4, TimeSymbol.Fractional, new boolean[]{true, false, false}); /** 4/4 time. */ public static final TimeType time_4_4 = new TimeType(4, 4, TimeSymbol.Fractional, new boolean[]{true, false, false, false}); /** 6/8 time. */ public static final TimeType time_6_8 = new TimeType(6, 8, TimeSymbol.Fractional, new boolean[]{true, false, false, true, false, false}); /** Common time. */ public static final TimeType timeCommon = new TimeType(4, 4, TimeSymbol.Common, new boolean[]{true, false, false, false}); /** Alla breve time. */ public static final TimeType timeAllaBreve = new TimeType(2, 2, TimeSymbol.AllaBreve, new boolean[]{true, false}); /** Senza misura. */ public static final TimeType timeSenzaMisura = new TimeType(0, 0, TimeSymbol.None, new boolean[0]); //list of known time types with numerator/denominator private static final TimeType[] knownTypes = {time_2_2, time_2_4, time_3_4, time_4_4, time_6_8}; /** The time fraction (numerator and denominator). * The beats per measure this time signature allows, e.g. (4/4) or (3/4). * 0 means: Undefined, so as many beats as needed are allowed. */ private final int numerator, denominator; /** The symbol of this time signature. For example, a (2/2) time may be represented * by a normal fraction or or by a alla breve symbol. */ private final TimeSymbol symbol; /** The accentuation of each beat. For example, usually a 4/4 time has <code>[x . . .]</code> * and 6/8 has <code>[x . . x . .]</code>. <code>x</code> means accentuated (true in the array), * <code>.</code> means unaccentuated (false in the array). * If there are no beats (senza misura), the array is empty. */ private final boolean[] beatsAccentuation; /** * Returns a {@link TimeType} with the given numerator and denominator. */ public static TimeType timeType(int numerator, int denominator) { //look for existing instance for (TimeType t : knownTypes) if (t.numerator == numerator && t.denominator == denominator) return t; //create new TimeType. only the first beat is accentuated. boolean[] beatsAccentuation = new boolean[numerator]; if (denominator > 0) beatsAccentuation[0] = true; return new TimeType(numerator, denominator, TimeSymbol.Fractional, beatsAccentuation); } /** * Gets the beats of a measure in this time, or null for senza misura. */ public Fraction getMeasureBeats() { if (numerator == 0 || denominator == 0) return null; return fr(numerator, denominator); } }