#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright 2020 , Nils Hilbricht , Germany ( https : / / www . hilbricht . net )
This file is part of the Laborejo Software Suite ( https : / / www . laborejo . org ) ,
This application is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : / / www . gnu . org / licenses / > .
"""
"""
This file handles various durations and their conversions .
"""
import logging ; logger = logging . getLogger ( __name__ ) ; logger . info ( " import " )
from engine . config import METADATA
#Suggested import in other files:
#from template.engine.duration import DB, DL, D1, D2, D4, D8, D16, D32, D64, D128
#import template.engine.duration as duration
MAXIMUM_TICK_DURATION = 2 * * 31 - 1
D4 = METADATA [ " quarterNoteInTicks " ]
D8 = int ( D4 / 2 )
D16 = int ( D8 / 2 )
D32 = int ( D16 / 2 )
D64 = int ( D32 / 2 )
D128 = int ( D64 / 2 )
D256 = int ( D128 / 2 )
D512 = int ( D256 / 2 )
D1024 = int ( D512 / 2 ) # set this to a number with many factors, like 210. According to http://homes.sice.indiana.edu/donbyrd/CMNExtremes.htm this is the real world limit.
if not int ( D1024 ) == D1024 :
logger . error ( f " Warning: Lowest duration D0124 has decimal places: { D0124 } but should be a plain integer. Your D4 value: { D4 } has not enough 2^n factors. " )
D2 = D4 * 2
D1 = D2 * 2
DB = D1 * 2 #Breve
DL = DB * 2 #Longa
DM = DL * 2 #Maxima
if not int ( D128 ) == D128 :
raise ValueError ( f " Durations must be integers (or .0). Yours: { D128 } " )
D_BASE_DURATIONS = ( D1024 , D512 , D256 , D64 , D32 , D16 , D8 , D4 , D2 , D1 , DB , DL , DM )
#Duration Keywords
D_DEFAULT = 0
D_STACCATO = 1
D_TENUTO = 2
D_TIE = 3
def _baseDurationToTraditionalNumber ( baseDuration ) :
""" 4 = Quarter, 8 = Eighth, 0 = Brevis, -1= Longa
Created in the loop below on startup """
if baseDuration == D4 :
return 4
elif baseDuration == D8 :
return 8
elif baseDuration == D16 :
return 16
elif baseDuration == D2 :
return 2
elif baseDuration == D1 :
return 1
elif baseDuration == DB :
return 0
elif baseDuration == DL :
return - 1
elif baseDuration == DM :
return - 2
elif baseDuration == D32 :
return 32
elif baseDuration == D64 :
return 64
elif baseDuration == D128 :
return 128
elif baseDuration == D256 :
return 256
elif baseDuration == D512 :
return 512
elif baseDuration == D1024 :
return 1024
elif baseDuration == 0 : #for KeySignatures and chords on init etc.
return 0
else :
raise ValueError ( " baseDuration does not match any traditioanl note duration value " )
baseDurations = ( 0 , D1024 , D512 , D256 , D128 , D64 , D32 , D16 , D8 , D4 , D2 , D1 , DB , DL , DM ) #from constants.py
baseDurationToTraditionalNumber = { }
for baseDuration in baseDurations :
baseDurationToTraditionalNumber [ baseDuration ] = _baseDurationToTraditionalNumber ( baseDuration )
traditionalNumberToBaseDuration = { }
for baseDuration in baseDurations :
traditionalNumberToBaseDuration [ _baseDurationToTraditionalNumber ( baseDuration ) ] = baseDuration
def jackBBTicksToDuration ( beatTypeAsTraditionalNumber , jackTicks , jackBeatTicks ) :
if None in ( beatTypeAsTraditionalNumber , jackTicks , jackBeatTicks ) :
return None
else :
beatTypeDuration = traditionalNumberToBaseDuration [ beatTypeAsTraditionalNumber ]
#print (beatTypeAsTraditionalNumber, beatTypeDuration, jackTicks, jackBeatTicks)
factor = beatTypeDuration / jackBeatTicks
return jackTicks * factor