Home | History | Annotate | Download | only in JetCreator
      1 """
      2  File:  
      3  JetUtils.py
      4  
      5  Contents and purpose:
      6  Utilities used throughout JetCreator
      7  
      8  Copyright (c) 2008 Android Open Source Project
      9  
     10  Licensed under the Apache License, Version 2.0 (the "License");
     11  you may not use this file except in compliance with the License.
     12  You may obtain a copy of the License at
     13  
     14       http://www.apache.org/licenses/LICENSE-2.0
     15  
     16  Unless required by applicable law or agreed to in writing, software
     17  distributed under the License is distributed on an "AS IS" BASIS,
     18  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     19  See the License for the specific language governing permissions and
     20  limitations under the License.
     21 """
     22 
     23 from __future__ import with_statement
     24 
     25 import wx
     26 import os
     27 import copy
     28 import ConfigParser
     29 import logging
     30 import time
     31 import tempfile
     32   
     33 from JetDefs import *
     34 from JetDebug import *
     35 from midifile import TimeBase, trackGrid
     36 
     37 class JetCutCopy(object):
     38     """ Handles cut/copy/pasting of events and segments """
     39     def __init__ (self, objType, objSave, currentSegmentName):
     40         self.objType = objType
     41         self.objSave = copy.deepcopy(objSave)
     42         self.currentSegmentName = currentSegmentName
     43     
     44     def GetObj(self, objList):
     45         """ Gets an object """
     46         objSave = copy.deepcopy(self.objSave)
     47         if self.objType == JetDefs.MAIN_SEGLIST:
     48             oldName = objSave.segname
     49             i = len(oldName) - 1
     50             while i > 0:
     51                 if not oldName[i].isdigit():
     52                     break
     53                 i = i - 1
     54             oldName = oldName[0:i+1]
     55             i = 1
     56             while True:
     57                 newName = oldName + str(i)
     58                 if self.UniqueSegName(newName, objList):
     59                     break  
     60                 i = i + 1
     61             objSave.segname = newName
     62         elif self.objType == JetDefs.MAIN_EVENTLIST:
     63             oldName = objSave.event_name
     64             i = len(oldName) - 1
     65             while i > 0:
     66                 if not oldName[i].isdigit():
     67                     break
     68                 i = i - 1
     69             oldName = oldName[0:i+1]
     70             i = 1
     71             while True:
     72                 newName = oldName + str(i)
     73                 if self.UniqueEventName(newName, objList):
     74                     break  
     75                 i = i + 1
     76             objSave.event_name = newName
     77         return objSave
     78     
     79     def UniqueSegName(self, nameVal, seglist):
     80         for nm in seglist:
     81             if nm.segname == nameVal:
     82                 return False
     83         return True
     84 
     85     def UniqueEventName(self, nameVal, eventlist):
     86         for nm in eventlist:
     87             if nm.event_name == nameVal:
     88                 return False
     89         return True
     90         
     91     
     92 class JetState(object):
     93     """ Saves the state for cut/copy/paste """
     94     def __init__ (self, jet_file, currentSegmentIndex, currentEventIndex):
     95         self.jet_file = copy.deepcopy(jet_file)
     96         self.currentSegmentIndex = currentSegmentIndex
     97         self.currentEventIndex = currentEventIndex
     98         
     99 def Queue (jet, queueSeg):
    100     """ Queues a segment """
    101     jet.QueueSegment(queueSeg.userID, queueSeg.seg_num, queueSeg.dls_num, queueSeg.repeat, queueSeg.transpose, queueSeg.mute_flags)
    102 
    103 class QueueSeg(object):
    104     """ Object representing a segment """
    105     def __init__ (self, name, userID, seg_num, dls_num=-1, repeat=0, transpose=0, mute_flags=0, status=''):
    106         self.name = name
    107         self.userID = userID
    108         self.seg_num = seg_num
    109         self.dls_num = dls_num
    110         self.repeat = repeat
    111         self.transpose = transpose
    112         self.mute_flags = mute_flags
    113         self.status = status
    114         #DumpQueueSeg(self)

    115 
    116 def FindDlsNum(libraries, dlsfile):
    117     """ Looks for a dls file in the library list """
    118     for index, library in enumerate(libraries):
    119         if library == dlsfile:
    120             return index
    121     return -1
    122 
    123 def SetRowSelection(list, row, state):
    124     """ Sets the selection status of a list row """
    125     if state:
    126         list.SetItemState(row, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
    127     else:
    128         list.SetItemState(row, ~wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
    129 
    130 def ClearRowSelections(list):
    131     """ Clears the list rows selection status """
    132     index = list.GetFirstSelected()
    133     while index != -1:
    134         SetRowSelection(list, index, False)
    135         index = list.GetNextSelected(index)
    136     
    137 def getColumnText(list, index, col):
    138     """ Sets the text of a column """
    139     item = list.GetItem(index, col)
    140     return item.GetText()
    141         
    142 def getColumnValue(list, index, col):
    143     """ Gets the text of a column """
    144     item = list.GetItem(index, col)
    145     v = str(item.GetText())
    146     if len(v) > 0:
    147         return int(item.GetText())
    148     else:
    149         return 0
    150             
    151 def StrNoneChk(fld):
    152     """ Returns a blank string if none """
    153     if fld is None:
    154         return ""
    155     return str(fld)
    156 
    157 def ConvertStrTimeToTuple(s):
    158     """ Converts a string time to a tuple """
    159     try:
    160         measures, beats, ticks = s.split(':',3)
    161         return (int(measures), int(beats), int(ticks))
    162     except:
    163         return JetDefs.MBT_DEFAULT
    164 
    165 def FileRelativePath(target, base=os.curdir):
    166     """ Returns relative file path """
    167     if not os.path.exists(target):
    168         return target
    169 
    170     if not os.path.isdir(base):
    171         return target
    172 
    173     base_list = (os.path.abspath(base)).split(os.sep)
    174     target_list = (os.path.abspath(target)).split(os.sep)
    175     if os.name in ['nt','dos','os2'] and base_list[0] <> target_list[0]:
    176         return target
    177     for i in range(min(len(base_list), len(target_list))):
    178         if base_list[i] <> target_list[i]: break
    179     else:
    180         i+=1
    181     rel_list = [os.pardir] * (len(base_list)-i) + target_list[i:]
    182     return os.path.join(*rel_list)
    183 
    184 def FileFixPath(fileSpec):
    185     """ Tweaks slashes """
    186     return fileSpec.replace("\\", "/")
    187     
    188 def FileKillClean(fileName):
    189     """ Deletes a file skipping errors """
    190     try:
    191         os.remove(fileName)
    192     except:
    193         pass
    194 
    195 def FileJustRoot(fileName):
    196     """ Gets just the root of the file name """
    197     try:
    198         return os.path.splitext(fileName)[0]
    199     except:
    200         return ""
    201     
    202 def FileJustName(fileName):
    203     """ Gets just the filename, without the path """
    204     try:
    205         return os.path.split(fileName)[1]
    206     except:
    207         return ""
    208 
    209 def FileJustPath(fileName):
    210     """ Gets just the path, without the file name """
    211     try:
    212         return os.path.split(fileName)[0]
    213     except:
    214         return ""  
    215 
    216 def FileJustExt(fileName):
    217     """ Gets just the extension of the file """
    218     try:
    219         ext = os.path.splitext(fileName)[1]
    220         return ext.upper()
    221     except:
    222         return ""
    223     
    224 def FileDateTime(fileName):
    225     """ Gets the date/time of a file """
    226     try:
    227         filetime = time.ctime(os.path.getmtime(fileName))
    228         return filetime
    229     except:
    230         return ""
    231 
    232 def FileExists(fileName):
    233     """ Checks if a file exists """
    234     try:
    235         return os.path.exists(fileName)
    236     except:
    237         return False
    238     
    239 def IniSetValue(configFile, section, option, value):
    240     """ Sets the value of a config file field """
    241     config = ConfigParser.ConfigParser()
    242     config.read(configFile)
    243     if not config.has_section(section):
    244         config.add_section(section)
    245     config.set(section, option, value)
    246     cfgfile = open(configFile,'w')
    247     config.write(cfgfile)
    248     cfgfile.close()
    249 
    250 def IniGetValue(configFile, section, option, retType='str', default=''):
    251     """ Gets the value of a config file field """
    252     ret = default
    253     config = ConfigParser.ConfigParser()
    254     config.read(configFile)
    255     if config.has_section(section):
    256         if config.has_option(section, option):
    257             ret = config.get(section, option)
    258     if retType =='int':
    259         try:
    260             ret = int(ret)
    261         except:
    262             ret = 0   
    263     elif retType == 'float':
    264         try:
    265             ret = float(ret)
    266         except:
    267             ret = 0   
    268     elif retType == 'bool':
    269         try:
    270             if ret[0].upper()=='T':
    271                 ret = True
    272             else:
    273                 ret = False
    274         except:
    275             ret = False    
    276     elif retType == 'list':
    277         try:
    278             ret = eval(ret)
    279         except:
    280             ret = []    
    281     return ret
    282     
    283 def GetRecentJetFiles():
    284     """ Builds a list of recent jet files """
    285     fileList = []
    286     config = ConfigParser.ConfigParser()
    287     config.read(JetDefs.JETCREATOR_INI)
    288     if config.has_section(JetDefs.RECENT_SECTION):
    289         for count in range(0, 10):
    290             sFile = "File" + str(count)
    291             if config.has_option(JetDefs.RECENT_SECTION, sFile):
    292                 sFileName = config.get(JetDefs.RECENT_SECTION, sFile)
    293                 if FileExists(sFileName):
    294                     if sFileName != JetDefs.UNTITLED_FILE:
    295                         #fileList.append(FileRelativePath(config.get(JetDefs.RECENT_SECTION, sFile)))

    296                         fileList.append(config.get(JetDefs.RECENT_SECTION, sFile))
    297     return fileList
    298     
    299 def AppendRecentJetFile(jetFile):
    300     """ Appends to a list of recent jet files """
    301     addedFiles = []
    302     fileList = GetRecentJetFiles()
    303     config = ConfigParser.ConfigParser()
    304     config.read(JetDefs.JETCREATOR_INI)
    305     if config.has_section(JetDefs.RECENT_SECTION):
    306         config.remove_section(JetDefs.RECENT_SECTION)
    307     config.add_section(JetDefs.RECENT_SECTION)
    308     config.set(JetDefs.RECENT_SECTION, "File0", jetFile)
    309     addedFiles.append(jetFile)
    310     count = 1
    311     for file in fileList:
    312         if file not in addedFiles:
    313             sFile = "File" + str(count)
    314             config.set(JetDefs.RECENT_SECTION, sFile, file)
    315             addedFiles.append(file)
    316             count += 1
    317     FileKillClean(JetDefs.JETCREATOR_INI)
    318     cfgfile = open(JetDefs.JETCREATOR_INI,'w')
    319     config.write(cfgfile)
    320     cfgfile.close()
    321     
    322 def CompareMbt(mbt1, mbt2):
    323     """ Compates to measure/beat/tick values """
    324     try:
    325         m1, b1, t1 = mbt1.split(':',3)
    326         m2, b2, t2 = mbt2.split(':',3)
    327         if int(m1) > int(m2):
    328             return False
    329         elif int(m1) == int(m2) and int(b1) > int(b2):
    330             return False
    331         elif int(b1) == int(b2) and int(t1) > int(t2):
    332             return False
    333         elif int(m1) == int(m2) and int(b1) == int(b2) and int(t1) == int(t2):
    334             return False
    335         else:
    336             return True
    337     except:
    338         return False
    339 
    340 def MbtVal(mbt):
    341     """ Converts mbts to ticks """
    342     if type(mbt).__name__=='str' or type(mbt).__name__=='unicode':
    343         mbt1 = mbt
    344     else:
    345         mbt1 = "%d:%d:%d" % mbt         
    346     try:
    347         return TimeBase().ConvertStrTimeToTicks(mbt1)
    348     except:
    349         return 0
    350 
    351 def TicksToMbt(ticks):
    352     """ Converts ticks to mbts """
    353     return TimeBase().ConvertTicksToMBT(ticks)
    354     
    355 def TicksToStrMbt(ticks):
    356     """ Converts ticks to mbts """
    357     return TimeBase().ConvertTicksToStr(ticks, '%02d:%02d:%02d')
    358     
    359 def MbtDifference(mbt1, mbt2):
    360     """ Returns difference between mbt values """
    361     return TimeBase().MbtDifference(mbt1, mbt2)
    362         
    363 def PlayMidiFile(midiFile, dlsFile=''):
    364     """ Plays a midi file """
    365     try:
    366         e = __import__('eas')
    367         
    368         if midiFile == '':
    369             return
    370         eas = e.EAS()
    371         if dlsFile > '':
    372             eas.LoadDLSCollection(dlsFile)
    373         eas.StartWave()
    374         audio_file = eas.OpenFile(midiFile)
    375         audio_file.Prepare()
    376         audio_file.Play()
    377         audio_file.Close()
    378         eas.StopWave()
    379         eas.Shutdown()
    380     except:
    381         return
    382     
    383 def SegmentOutputFile(segName, configFile):
    384     """ Computes a segment output file """
    385     configPath = FileJustPath(configFile) + "/"
    386     segOutput = configPath + "Seg_" + segName + ".mid"
    387     return segOutput
    388 
    389 def ComputeMuteFlags(jet_file, segName):
    390     """ Computes mute flags """
    391     muteFlag = 0
    392     for jet_event in jet_file.GetEvents(segName):
    393         muteFlag = SetMute(jet_event.track_num, muteFlag)
    394     return muteFlag
    395 
    396 def ComputeMuteFlagsFromList1(list):
    397     """ Computes mute flags from a list """
    398     muteFlag = 0
    399     num = list.GetItemCount()
    400     for iRow in range(num):
    401         track_num = list.GetTrackNumber(iRow)
    402         if list.IsChecked(iRow):
    403             muteFlag = SetMute(track_num, muteFlag)
    404         else:
    405             muteFlag = ClearMute(track_num, muteFlag)
    406     return muteFlag
    407 
    408 def ComputeMuteFlagsFromList(list):
    409     """ Computes mute flags from a list """
    410     muteFlags = 0
    411     num = list.GetItemCount()
    412     for iRow in range(num):
    413         track_num = list.GetTrackNumber(iRow)
    414         if list.IsChecked(iRow):
    415             muteFlags = SetMute(track_num, muteFlags)            
    416     return muteFlags
    417  
    418 
    419 def SetMuteFlag(track, muteFlag, mute): 
    420     """ Sets a mute flag """
    421     if mute:
    422         SetMute(track, muteFlag) 
    423     else:
    424         ClearMute(track, muteFlag)  
    425         
    426 def SetMute(track, muteFlag):
    427     """ Sets a mute flag """
    428     try:
    429         muteFlag |= 1 << (track)
    430         return muteFlag
    431     except:
    432         #bad argument

    433         return muteFlag
    434 
    435 def ClearMute(track, muteFlag):
    436     """ Clears a mute flag """
    437     try:
    438         muteFlag &= ~(1 << (track))
    439         return muteFlag;
    440     except:
    441         #bad argument

    442         return muteFlag
    443 
    444 def GetMute(track, muteFlag):
    445     """ Get a mute flag """
    446     try:
    447         if (muteFlag & ( 1 << (track))) == 0:
    448             return False
    449         else:
    450             return True
    451     except:
    452         #bad argument

    453         return False
    454 
    455 def InfoMsg(msgTitle, msgText):
    456     """ Display a simple informational message """
    457     dlg = wx.MessageDialog(None,
    458                            message=msgText,
    459                            caption=msgTitle,
    460                            style=wx.OK|wx.ICON_INFORMATION
    461                            )
    462     dlg.ShowModal()
    463     dlg.Destroy()
    464     
    465 def SendEvent (mycontrol, evt):
    466     """ Sends an event """
    467     cmd = wx.CommandEvent(evt)
    468     cmd.SetEventObject(mycontrol)
    469     cmd.SetId(mycontrol.GetId())
    470     mycontrol.GetEventHandler().ProcessEvent(cmd)
    471         
    472 def GetJetHelpText(dlgName, fld):
    473     """ Gets the jet help text file """
    474     return IniGetValue(JetDefs.JETCREATOR_HLP, dlgName, fld)
    475 
    476 def ExportJetArchive(fileName, jetConfigFile, jetFile):
    477     """ Exports all files into a zip archive file """
    478     z = __import__('zipfile')
    479     zip = z.ZipFile(fileName, 'w')
    480 
    481     #zip the original .JET file

    482     if FileExists(jetFile.config.filename):
    483         zip.write(jetFile.config.filename, FileJustName(jetFile.config.filename))
    484     
    485     #make copy of object so we can modify it

    486     jet_file = copy.deepcopy(jetFile)
    487     
    488     #zip the files, without paths

    489     for segment in jet_file.GetSegments():
    490         if FileExists(segment.filename):
    491             if not FileJustName(segment.filename) in zip.namelist():
    492                 zip.write(segment.filename, FileJustName(segment.filename))
    493         if FileExists(segment.output):
    494             if not FileJustName(segment.output) in zip.namelist():
    495                 zip.write(segment.output, FileJustName(segment.output))
    496     
    497     #zip the library files

    498     for library in jet_file.GetLibraries():
    499         if FileExists(library):
    500             if not FileJustName(library) in zip.namelist():
    501                 zip.write(library, FileJustName(library))
    502     
    503     #remove the paths on filenames

    504     for segment in jet_file.GetSegments():
    505         segment.filename = FileJustName(segment.filename)
    506         segment.dlsfile = FileJustName(segment.dlsfile)
    507         segment.output = FileJustName(segment.output)
    508     
    509     #remove paths

    510     for index, library in enumerate(jet_file.libraries):
    511         jet_file.libraries[index] = FileJustName(library)
    512         
    513     #create temporary .JTC file so we can modify paths to files

    514     tmpConfigFile = JetDefs.TEMP_JET_CONFIG_FILE
    515     FileKillClean(tmpConfigFile)
    516     
    517     #save the file

    518     jet_file.SaveJetConfig(tmpConfigFile)
    519     
    520     #zip it and rename it back to original name without path

    521     zip.write(tmpConfigFile, FileJustName(jetConfigFile))
    522      
    523     #create a flag file so we know this is a jet archive

    524     zip.write(tmpConfigFile, "JetArchive")
    525      
    526     zip.close()
    527 
    528     FileKillClean(tmpConfigFile)
    529     
    530 def ValidateConfig(test_jet_file):
    531     """ Validates the contents of a config file """
    532     dImp = __import__('JetDialogs')
    533     errors = []
    534     fatalError = False
    535     for segment in test_jet_file.segments:
    536         logging.debug(segment.filename)
    537         if segment.filename is not None and len(segment.filename) > 0 and not FileExists(segment.filename):
    538             errors.append(("Segment MIDI file not found", segment.filename))
    539             fatalError = True
    540         if segment.dlsfile is not None and len(segment.dlsfile) > 0 and not FileExists(segment.dlsfile):
    541             errors.append(("Segment DLS file not found; removing from config", segment.dlsfile))
    542             segment.dlsfile = ""
    543            
    544     logging.debug(test_jet_file.config.filename)
    545         
    546     if len(errors) == 0:
    547         return True
    548     else:
    549         dlg = dImp.JetErrors("Jet Definition File Errors")
    550         dlg.SetErrors(errors)
    551         result = dlg.ShowModal()
    552         dlg.Destroy()
    553         if fatalError:
    554             return False
    555         else:
    556             return True
    557         
    558 def release_getLogger(name):
    559     """  passing original handler with debug() method replaced to empty function """
    560 
    561     def dummy(*k, **kw):
    562         pass
    563 
    564     global __orig_getLogger
    565     log = __orig_getLogger(name)
    566     setattr(log, 'debug', dummy)
    567     setattr(log, 'info', dummy)
    568     setattr(log, 'error', dummy)
    569     setattr(log, 'critical', dummy)
    570     return log
    571 
    572 def install_release_loggers():
    573     """ Save original handler, installs newer one """
    574     global __orig_getLogger
    575     __orig_getLogger = logging.getLogger
    576     setattr(logging, 'getLogger', release_getLogger)
    577 
    578 def restore_getLogger():
    579     """ Restores original handler """
    580     global __orig_getLogger
    581     if __orig_getLogger:
    582         setattr(logging, 'getLogger', __orig_getLogger)
    583 
    584 def GetMidiFileLength(midiFile):
    585     """ Gets the length of a midi file via eas """
    586     e = __import__('eas')
    587        
    588     if not FileExists(midiFile):
    589         return 0 
    590     
    591     eas = e.EAS()
    592     audio_file = eas.OpenFile(midiFile)
    593     audio_file.Prepare()
    594     midiLength = eas.audio_streams[0].ParseMetaData()
    595     audio_file.Close()
    596     eas.Shutdown()
    597     return midiLength
    598 
    599 def GetMidiInfo(midiFile):
    600     """ Gets midi file info """
    601     m = __import__('midifile')
    602     md = m.GetMidiInfo(midiFile)
    603     return md
    604 
    605 def PrintMidiInfo(midiFile):
    606     """ Prints info about a midi file """
    607     mi = GetMidiInfo(midiFile)
    608     if mi.err == 0:
    609         print("ppqn: " + str(mi.ppqn))
    610         print("beats_per_measure: " + str(mi.beats_per_measure))
    611         print("ending mbt: " + str(mi.endMbt))
    612         print("ending mbt str: " + mi.endMbtStr)
    613         print("maxMeasures: " + str(mi.maxMeasures))
    614         print("maxBeats: " + str(mi.maxBeats))
    615         print("maxTicks: " + str(mi.maxTicks))
    616         print("maxTracks: " + str(mi.maxTracks))
    617         print("totalTicks: " + str(mi.totalTicks))   
    618         for track in mi.trackList:
    619             print(track)
    620     else:
    621         print("Error opening") 
    622     
    623 def MidiSegInfo(segment):
    624     """ Midi file info saved in config file for speed """
    625     class segInfo:
    626         iMsPerTick = 0
    627         bpm = 4
    628         ppqn = 480
    629         total_ticks = 0
    630         iLengthInMs = 0
    631         iTracks = 0
    632         trackList = []
    633     
    634     ver = "1.5"
    635     ret = segInfo()
    636     savedVer = IniGetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "Ver")
    637     savedDateTime = IniGetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "DateTime")
    638     dateTime = FileDateTime(segment.filename)
    639     if ver != savedVer or dateTime != savedDateTime:
    640         mi = GetMidiInfo(segment.filename)
    641         if mi.err == 0:
    642             IniSetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "Ver", ver)
    643             IniSetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "DateTime", str(dateTime))
    644             IniSetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "PPQN", str(mi.ppqn))
    645             IniSetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "BPM", str(mi.beats_per_measure))
    646             IniSetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "totalTicks", str(mi.totalTicks))
    647             IniSetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "maxTracks", str(mi.maxTracks))
    648             iLengthInMs = GetMidiFileLength(segment.filename) * 1000
    649             IniSetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "LengthInMs", str(iLengthInMs))
    650             if iLengthInMs > 0:
    651                 IniSetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "MsPerTick", str(iLengthInMs / mi.totalTicks))
    652             #have to write out the tracklist in format that can be saved in INI file

    653             tl = []
    654             for track in mi.trackList:
    655                 tl.append((track.track, track.channel, track.name))
    656             IniSetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "Tracks", tl)
    657             
    658     trackList = []
    659     tl = IniGetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "Tracks", 'list', [])
    660     for t in tl:
    661         trackList.append(trackGrid(t[0], t[1], t[2],False))
    662     iTracks = IniGetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "maxTracks", 'int', 0)
    663     iMsPerTick = IniGetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "MsPerTick", 'float', 0)
    664     bpm = IniGetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "BPM", 'int', 0)
    665     ppqn = IniGetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "PPQN", 'int', 480)
    666     if iMsPerTick == 0 or bpm == 0 or ppqn == 0:
    667         return ret
    668     tb = TimeBase(ppqn, bpm)
    669     total_ticks = tb.ConvertStrTimeToTicks(segment.length)
    670     if total_ticks == 0:
    671         total_ticks = tb.MbtDifference(tb.ConvertStrTimeToTuple(segment.start), tb.ConvertStrTimeToTuple(segment.end))
    672     if total_ticks == 0:
    673         return ret
    674 
    675     ret.iTracks = iTracks
    676     ret.iMsPerTick = iMsPerTick
    677     ret.bpm = bpm
    678     ret.ppqn = ppqn
    679     ret.total_ticks = total_ticks
    680     ret.iLengthInMs = total_ticks * iMsPerTick
    681     ret.trackList = trackList
    682     return ret
    683     
    684 def TimeStr(ms):
    685     """ Returns a time string """
    686     s=ms/1000
    687     m,s=divmod(s,60)
    688     h,m=divmod(m,60)
    689     d,h=divmod(h,24)
    690     if m > 0:
    691         return "%d Min %d Sec" % (m,s)
    692     else:
    693         return "%d Seconds" % (s)
    694         
    695 def mbtFct(mbt, mod):
    696     """ Converts times """
    697     if type(mbt).__name__=='str' or type(mbt).__name__=='unicode':
    698         mbt = ConvertStrTimeToTuple(mbt)
    699         retType = 'str'
    700     else:
    701         retType = 'int'
    702         
    703     m = mbt[0]+mod
    704     b = mbt[1]+mod
    705     t = mbt[2]
    706     if m < 0:
    707         m = 0
    708     if b < 0:
    709         b = 0
    710     if b > 4:
    711         b = 4
    712     if t < 0:
    713         t = 0
    714         
    715     if retType == 'str':    
    716         return "%d:%d:%d" % (m, b, t)
    717     else:
    718         return (m, b, t)
    719  
    720 def OsWindows():
    721     """ Tells us whether windows or os x """
    722     if os.name == 'nt':
    723         return True ;
    724     else:
    725         return False ;
    726       
    727 def MacOffset():
    728     """ Mac screen coordinates funky on some controls so we finagle a few pixels """
    729     if not OsWindows():
    730         return 3
    731     else:
    732         return 0
    733     
    734 def SafeJetShutdown(lock, jet):
    735     """ Makes sure we do the jet shutdown properly """
    736     with lock:
    737         #MAKE SURE WE CLEANUP

    738         #try: jet.Clear_Queue()

    739         #except: pass

    740         
    741         try: jet.eas.StopWave()
    742         except: pass
    743         
    744         try: jet.Shutdown()
    745         except: pass
    746 
    747         jet = None
    748     
    749     
    750 def CreateTempJetFile(org_jet_file):
    751     """ Creates temporary jet file for playback testing """
    752     dirname = JetDefs.TEMP_JET_DIR
    753     if not os.path.isdir(dirname):
    754         os.mkdir(dirname)
    755         
    756     tmpConfigFile = dirname + FileJustName(org_jet_file.config_file)
    757     FileKillClean(tmpConfigFile)
    758     
    759     jet_file = copy.deepcopy(org_jet_file)
    760     
    761     for tmp in jet_file.segments:
    762         tmp.output = dirname + FileJustName(tmp.output)
    763     
    764     jet_file.config_file = tmpConfigFile        
    765     jet_file.config.filename = dirname + FileJustName(jet_file.config.filename)
    766     FileKillClean(jet_file.config.filename)
    767     
    768     jet_file.SaveJetConfig(tmpConfigFile)
    769     jet_file.WriteJetFileFromConfig(tmpConfigFile)
    770 
    771     return jet_file
    772     
    773 def CleanupTempJetFile(jet_file):
    774     """ Cleans up temporary files """
    775     FileKillClean(jet_file.config.filename)
    776     FileKillClean(jet_file.config_file)
    777     for tmp in jet_file.segments:
    778         FileKillClean(tmp.output)
    779 
    780 def GetNow():
    781     return time.asctime()
    782 
    783 
    784 if __name__ == '__main__':
    785     """ Tests functions """
    786     pass
    787      
    788