From 8df4ccb34061ac9b18f800cccd58fed52a7038f8 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi <> Date: Fri, 3 Apr 2009 18:25:35 -0700 Subject: AI 144575: am: CL 144573 Checking in Sonivox' JetCreator code. Original author: jmtrivi Merged from: //branches/cupcake/... Automated import of CL 144575 --- jet_tools/JetCreator/JetUtils.py | 788 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 788 insertions(+) create mode 100755 jet_tools/JetCreator/JetUtils.py (limited to 'jet_tools/JetCreator/JetUtils.py') diff --git a/jet_tools/JetCreator/JetUtils.py b/jet_tools/JetCreator/JetUtils.py new file mode 100755 index 0000000..d81e34d --- /dev/null +++ b/jet_tools/JetCreator/JetUtils.py @@ -0,0 +1,788 @@ +""" + File: + JetUtils.py + + Contents and purpose: + Utilities used throughout JetCreator + + Copyright (c) 2008 Android Open Source Project + + 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. +""" + +from __future__ import with_statement + +import wx +import os +import copy +import ConfigParser +import logging +import time +import tempfile + +from JetDefs import * +from JetDebug import * +from midifile import TimeBase, trackGrid + +class JetCutCopy(object): + """ Handles cut/copy/pasting of events and segments """ + def __init__ (self, objType, objSave, currentSegmentName): + self.objType = objType + self.objSave = copy.deepcopy(objSave) + self.currentSegmentName = currentSegmentName + + def GetObj(self, objList): + """ Gets an object """ + objSave = copy.deepcopy(self.objSave) + if self.objType == JetDefs.MAIN_SEGLIST: + oldName = objSave.segname + i = len(oldName) - 1 + while i > 0: + if not oldName[i].isdigit(): + break + i = i - 1 + oldName = oldName[0:i+1] + i = 1 + while True: + newName = oldName + str(i) + if self.UniqueSegName(newName, objList): + break + i = i + 1 + objSave.segname = newName + elif self.objType == JetDefs.MAIN_EVENTLIST: + oldName = objSave.event_name + i = len(oldName) - 1 + while i > 0: + if not oldName[i].isdigit(): + break + i = i - 1 + oldName = oldName[0:i+1] + i = 1 + while True: + newName = oldName + str(i) + if self.UniqueEventName(newName, objList): + break + i = i + 1 + objSave.event_name = newName + return objSave + + def UniqueSegName(self, nameVal, seglist): + for nm in seglist: + if nm.segname == nameVal: + return False + return True + + def UniqueEventName(self, nameVal, eventlist): + for nm in eventlist: + if nm.event_name == nameVal: + return False + return True + + +class JetState(object): + """ Saves the state for cut/copy/paste """ + def __init__ (self, jet_file, currentSegmentIndex, currentEventIndex): + self.jet_file = copy.deepcopy(jet_file) + self.currentSegmentIndex = currentSegmentIndex + self.currentEventIndex = currentEventIndex + +def Queue (jet, queueSeg): + """ Queues a segment """ + jet.QueueSegment(queueSeg.userID, queueSeg.seg_num, queueSeg.dls_num, queueSeg.repeat, queueSeg.transpose, queueSeg.mute_flags) + +class QueueSeg(object): + """ Object representing a segment """ + def __init__ (self, name, userID, seg_num, dls_num=-1, repeat=0, transpose=0, mute_flags=0, status=''): + self.name = name + self.userID = userID + self.seg_num = seg_num + self.dls_num = dls_num + self.repeat = repeat + self.transpose = transpose + self.mute_flags = mute_flags + self.status = status + #DumpQueueSeg(self) + +def FindDlsNum(libraries, dlsfile): + """ Looks for a dls file in the library list """ + for index, library in enumerate(libraries): + if library == dlsfile: + return index + return -1 + +def SetRowSelection(list, row, state): + """ Sets the selection status of a list row """ + if state: + list.SetItemState(row, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED) + else: + list.SetItemState(row, ~wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED) + +def ClearRowSelections(list): + """ Clears the list rows selection status """ + index = list.GetFirstSelected() + while index != -1: + SetRowSelection(list, index, False) + index = list.GetNextSelected(index) + +def getColumnText(list, index, col): + """ Sets the text of a column """ + item = list.GetItem(index, col) + return item.GetText() + +def getColumnValue(list, index, col): + """ Gets the text of a column """ + item = list.GetItem(index, col) + v = str(item.GetText()) + if len(v) > 0: + return int(item.GetText()) + else: + return 0 + +def StrNoneChk(fld): + """ Returns a blank string if none """ + if fld is None: + return "" + return str(fld) + +def ConvertStrTimeToTuple(s): + """ Converts a string time to a tuple """ + try: + measures, beats, ticks = s.split(':',3) + return (int(measures), int(beats), int(ticks)) + except: + return JetDefs.MBT_DEFAULT + +def FileRelativePath(target, base=os.curdir): + """ Returns relative file path """ + if not os.path.exists(target): + return target + + if not os.path.isdir(base): + return target + + base_list = (os.path.abspath(base)).split(os.sep) + target_list = (os.path.abspath(target)).split(os.sep) + if os.name in ['nt','dos','os2'] and base_list[0] <> target_list[0]: + return target + for i in range(min(len(base_list), len(target_list))): + if base_list[i] <> target_list[i]: break + else: + i+=1 + rel_list = [os.pardir] * (len(base_list)-i) + target_list[i:] + return os.path.join(*rel_list) + +def FileFixPath(fileSpec): + """ Tweaks slashes """ + return fileSpec.replace("\\", "/") + +def FileKillClean(fileName): + """ Deletes a file skipping errors """ + try: + os.remove(fileName) + except: + pass + +def FileJustRoot(fileName): + """ Gets just the root of the file name """ + try: + return os.path.splitext(fileName)[0] + except: + return "" + +def FileJustName(fileName): + """ Gets just the filename, without the path """ + try: + return os.path.split(fileName)[1] + except: + return "" + +def FileJustPath(fileName): + """ Gets just the path, without the file name """ + try: + return os.path.split(fileName)[0] + except: + return "" + +def FileJustExt(fileName): + """ Gets just the extension of the file """ + try: + ext = os.path.splitext(fileName)[1] + return ext.upper() + except: + return "" + +def FileDateTime(fileName): + """ Gets the date/time of a file """ + try: + filetime = time.ctime(os.path.getmtime(fileName)) + return filetime + except: + return "" + +def FileExists(fileName): + """ Checks if a file exists """ + try: + return os.path.exists(fileName) + except: + return False + +def IniSetValue(configFile, section, option, value): + """ Sets the value of a config file field """ + config = ConfigParser.ConfigParser() + config.read(configFile) + if not config.has_section(section): + config.add_section(section) + config.set(section, option, value) + cfgfile = open(configFile,'w') + config.write(cfgfile) + cfgfile.close() + +def IniGetValue(configFile, section, option, retType='str', default=''): + """ Gets the value of a config file field """ + ret = default + config = ConfigParser.ConfigParser() + config.read(configFile) + if config.has_section(section): + if config.has_option(section, option): + ret = config.get(section, option) + if retType =='int': + try: + ret = int(ret) + except: + ret = 0 + elif retType == 'float': + try: + ret = float(ret) + except: + ret = 0 + elif retType == 'bool': + try: + if ret[0].upper()=='T': + ret = True + else: + ret = False + except: + ret = False + elif retType == 'list': + try: + ret = eval(ret) + except: + ret = [] + return ret + +def GetRecentJetFiles(): + """ Builds a list of recent jet files """ + fileList = [] + config = ConfigParser.ConfigParser() + config.read(JetDefs.JETCREATOR_INI) + if config.has_section(JetDefs.RECENT_SECTION): + for count in range(0, 10): + sFile = "File" + str(count) + if config.has_option(JetDefs.RECENT_SECTION, sFile): + sFileName = config.get(JetDefs.RECENT_SECTION, sFile) + if FileExists(sFileName): + if sFileName != JetDefs.UNTITLED_FILE: + #fileList.append(FileRelativePath(config.get(JetDefs.RECENT_SECTION, sFile))) + fileList.append(config.get(JetDefs.RECENT_SECTION, sFile)) + return fileList + +def AppendRecentJetFile(jetFile): + """ Appends to a list of recent jet files """ + addedFiles = [] + fileList = GetRecentJetFiles() + config = ConfigParser.ConfigParser() + config.read(JetDefs.JETCREATOR_INI) + if config.has_section(JetDefs.RECENT_SECTION): + config.remove_section(JetDefs.RECENT_SECTION) + config.add_section(JetDefs.RECENT_SECTION) + config.set(JetDefs.RECENT_SECTION, "File0", jetFile) + addedFiles.append(jetFile) + count = 1 + for file in fileList: + if file not in addedFiles: + sFile = "File" + str(count) + config.set(JetDefs.RECENT_SECTION, sFile, file) + addedFiles.append(file) + count += 1 + FileKillClean(JetDefs.JETCREATOR_INI) + cfgfile = open(JetDefs.JETCREATOR_INI,'w') + config.write(cfgfile) + cfgfile.close() + +def CompareMbt(mbt1, mbt2): + """ Compates to measure/beat/tick values """ + try: + m1, b1, t1 = mbt1.split(':',3) + m2, b2, t2 = mbt2.split(':',3) + if int(m1) > int(m2): + return False + elif int(m1) == int(m2) and int(b1) > int(b2): + return False + elif int(b1) == int(b2) and int(t1) > int(t2): + return False + elif int(m1) == int(m2) and int(b1) == int(b2) and int(t1) == int(t2): + return False + else: + return True + except: + return False + +def MbtVal(mbt): + """ Converts mbts to ticks """ + if type(mbt).__name__=='str' or type(mbt).__name__=='unicode': + mbt1 = mbt + else: + mbt1 = "%d:%d:%d" % mbt + try: + return TimeBase().ConvertStrTimeToTicks(mbt1) + except: + return 0 + +def TicksToMbt(ticks): + """ Converts ticks to mbts """ + return TimeBase().ConvertTicksToMBT(ticks) + +def TicksToStrMbt(ticks): + """ Converts ticks to mbts """ + return TimeBase().ConvertTicksToStr(ticks, '%02d:%02d:%02d') + +def MbtDifference(mbt1, mbt2): + """ Returns difference between mbt values """ + return TimeBase().MbtDifference(mbt1, mbt2) + +def PlayMidiFile(midiFile, dlsFile=''): + """ Plays a midi file """ + try: + e = __import__('eas') + + if midiFile == '': + return + eas = e.EAS() + if dlsFile > '': + eas.LoadDLSCollection(dlsFile) + eas.StartWave() + audio_file = eas.OpenFile(midiFile) + audio_file.Prepare() + audio_file.Play() + audio_file.Close() + eas.StopWave() + eas.Shutdown() + except: + return + +def SegmentOutputFile(segName, configFile): + """ Computes a segment output file """ + configPath = FileJustPath(configFile) + "/" + segOutput = configPath + "Seg_" + segName + ".mid" + return segOutput + +def ComputeMuteFlags(jet_file, segName): + """ Computes mute flags """ + muteFlag = 0 + for jet_event in jet_file.GetEvents(segName): + muteFlag = SetMute(jet_event.track_num, muteFlag) + return muteFlag + +def ComputeMuteFlagsFromList1(list): + """ Computes mute flags from a list """ + muteFlag = 0 + num = list.GetItemCount() + for iRow in range(num): + track_num = list.GetTrackNumber(iRow) + if list.IsChecked(iRow): + muteFlag = SetMute(track_num, muteFlag) + else: + muteFlag = ClearMute(track_num, muteFlag) + return muteFlag + +def ComputeMuteFlagsFromList(list): + """ Computes mute flags from a list """ + muteFlags = 0 + num = list.GetItemCount() + for iRow in range(num): + track_num = list.GetTrackNumber(iRow) + if list.IsChecked(iRow): + muteFlags = SetMute(track_num, muteFlags) + return muteFlags + + +def SetMuteFlag(track, muteFlag, mute): + """ Sets a mute flag """ + if mute: + SetMute(track, muteFlag) + else: + ClearMute(track, muteFlag) + +def SetMute(track, muteFlag): + """ Sets a mute flag """ + try: + muteFlag |= 1 << (track) + return muteFlag + except: + #bad argument + return muteFlag + +def ClearMute(track, muteFlag): + """ Clears a mute flag """ + try: + muteFlag &= ~(1 << (track)) + return muteFlag; + except: + #bad argument + return muteFlag + +def GetMute(track, muteFlag): + """ Get a mute flag """ + try: + if (muteFlag & ( 1 << (track))) == 0: + return False + else: + return True + except: + #bad argument + return False + +def InfoMsg(msgTitle, msgText): + """ Display a simple informational message """ + dlg = wx.MessageDialog(None, + message=msgText, + caption=msgTitle, + style=wx.OK|wx.ICON_INFORMATION + ) + dlg.ShowModal() + dlg.Destroy() + +def SendEvent (mycontrol, evt): + """ Sends an event """ + cmd = wx.CommandEvent(evt) + cmd.SetEventObject(mycontrol) + cmd.SetId(mycontrol.GetId()) + mycontrol.GetEventHandler().ProcessEvent(cmd) + +def GetJetHelpText(dlgName, fld): + """ Gets the jet help text file """ + return IniGetValue(JetDefs.JETCREATOR_HLP, dlgName, fld) + +def ExportJetArchive(fileName, jetConfigFile, jetFile): + """ Exports all files into a zip archive file """ + z = __import__('zipfile') + zip = z.ZipFile(fileName, 'w') + + #zip the original .JET file + if FileExists(jetFile.config.filename): + zip.write(jetFile.config.filename, FileJustName(jetFile.config.filename)) + + #make copy of object so we can modify it + jet_file = copy.deepcopy(jetFile) + + #zip the files, without paths + for segment in jet_file.GetSegments(): + if FileExists(segment.filename): + if not FileJustName(segment.filename) in zip.namelist(): + zip.write(segment.filename, FileJustName(segment.filename)) + if FileExists(segment.output): + if not FileJustName(segment.output) in zip.namelist(): + zip.write(segment.output, FileJustName(segment.output)) + + #zip the library files + for library in jet_file.GetLibraries(): + if FileExists(library): + if not FileJustName(library) in zip.namelist(): + zip.write(library, FileJustName(library)) + + #remove the paths on filenames + for segment in jet_file.GetSegments(): + segment.filename = FileJustName(segment.filename) + segment.dlsfile = FileJustName(segment.dlsfile) + segment.output = FileJustName(segment.output) + + #remove paths + for index, library in enumerate(jet_file.libraries): + jet_file.libraries[index] = FileJustName(library) + + #create temporary .JTC file so we can modify paths to files + tmpConfigFile = JetDefs.TEMP_JET_CONFIG_FILE + FileKillClean(tmpConfigFile) + + #save the file + jet_file.SaveJetConfig(tmpConfigFile) + + #zip it and rename it back to original name without path + zip.write(tmpConfigFile, FileJustName(jetConfigFile)) + + #create a flag file so we know this is a jet archive + zip.write(tmpConfigFile, "JetArchive") + + zip.close() + + FileKillClean(tmpConfigFile) + +def ValidateConfig(test_jet_file): + """ Validates the contents of a config file """ + dImp = __import__('JetDialogs') + errors = [] + fatalError = False + for segment in test_jet_file.segments: + logging.debug(segment.filename) + if segment.filename is not None and len(segment.filename) > 0 and not FileExists(segment.filename): + errors.append(("Segment MIDI file not found", segment.filename)) + fatalError = True + if segment.dlsfile is not None and len(segment.dlsfile) > 0 and not FileExists(segment.dlsfile): + errors.append(("Segment DLS file not found; removing from config", segment.dlsfile)) + segment.dlsfile = "" + + logging.debug(test_jet_file.config.filename) + + if len(errors) == 0: + return True + else: + dlg = dImp.JetErrors("Jet Definition File Errors") + dlg.SetErrors(errors) + result = dlg.ShowModal() + dlg.Destroy() + if fatalError: + return False + else: + return True + +def release_getLogger(name): + """ passing original handler with debug() method replaced to empty function """ + + def dummy(*k, **kw): + pass + + global __orig_getLogger + log = __orig_getLogger(name) + setattr(log, 'debug', dummy) + setattr(log, 'info', dummy) + setattr(log, 'error', dummy) + setattr(log, 'critical', dummy) + return log + +def install_release_loggers(): + """ Save original handler, installs newer one """ + global __orig_getLogger + __orig_getLogger = logging.getLogger + setattr(logging, 'getLogger', release_getLogger) + +def restore_getLogger(): + """ Restores original handler """ + global __orig_getLogger + if __orig_getLogger: + setattr(logging, 'getLogger', __orig_getLogger) + +def GetMidiFileLength(midiFile): + """ Gets the length of a midi file via eas """ + e = __import__('eas') + + if not FileExists(midiFile): + return 0 + + eas = e.EAS() + audio_file = eas.OpenFile(midiFile) + audio_file.Prepare() + midiLength = eas.audio_streams[0].ParseMetaData() + audio_file.Close() + eas.Shutdown() + return midiLength + +def GetMidiInfo(midiFile): + """ Gets midi file info """ + m = __import__('midifile') + md = m.GetMidiInfo(midiFile) + return md + +def PrintMidiInfo(midiFile): + """ Prints info about a midi file """ + mi = GetMidiInfo(midiFile) + if mi.err == 0: + print("ppqn: " + str(mi.ppqn)) + print("beats_per_measure: " + str(mi.beats_per_measure)) + print("ending mbt: " + str(mi.endMbt)) + print("ending mbt str: " + mi.endMbtStr) + print("maxMeasures: " + str(mi.maxMeasures)) + print("maxBeats: " + str(mi.maxBeats)) + print("maxTicks: " + str(mi.maxTicks)) + print("maxTracks: " + str(mi.maxTracks)) + print("totalTicks: " + str(mi.totalTicks)) + for track in mi.trackList: + print(track) + else: + print("Error opening") + +def MidiSegInfo(segment): + """ Midi file info saved in config file for speed """ + class segInfo: + iMsPerTick = 0 + bpm = 4 + ppqn = 480 + total_ticks = 0 + iLengthInMs = 0 + iTracks = 0 + trackList = [] + + ver = "1.5" + ret = segInfo() + savedVer = IniGetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "Ver") + savedDateTime = IniGetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "DateTime") + dateTime = FileDateTime(segment.filename) + if ver != savedVer or dateTime != savedDateTime: + mi = GetMidiInfo(segment.filename) + if mi.err == 0: + IniSetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "Ver", ver) + IniSetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "DateTime", str(dateTime)) + IniSetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "PPQN", str(mi.ppqn)) + IniSetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "BPM", str(mi.beats_per_measure)) + IniSetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "totalTicks", str(mi.totalTicks)) + IniSetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "maxTracks", str(mi.maxTracks)) + iLengthInMs = GetMidiFileLength(segment.filename) * 1000 + IniSetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "LengthInMs", str(iLengthInMs)) + if iLengthInMs > 0: + IniSetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "MsPerTick", str(iLengthInMs / mi.totalTicks)) + #have to write out the tracklist in format that can be saved in INI file + tl = [] + for track in mi.trackList: + tl.append((track.track, track.channel, track.name)) + IniSetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "Tracks", tl) + + trackList = [] + tl = IniGetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "Tracks", 'list', []) + for t in tl: + trackList.append(trackGrid(t[0], t[1], t[2],False)) + iTracks = IniGetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "maxTracks", 'int', 0) + iMsPerTick = IniGetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "MsPerTick", 'float', 0) + bpm = IniGetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "BPM", 'int', 0) + ppqn = IniGetValue(JetDefs.JETMIDIFILES_INI, segment.filename, "PPQN", 'int', 480) + if iMsPerTick == 0 or bpm == 0 or ppqn == 0: + return ret + tb = TimeBase(ppqn, bpm) + total_ticks = tb.ConvertStrTimeToTicks(segment.length) + if total_ticks == 0: + total_ticks = tb.MbtDifference(tb.ConvertStrTimeToTuple(segment.start), tb.ConvertStrTimeToTuple(segment.end)) + if total_ticks == 0: + return ret + + ret.iTracks = iTracks + ret.iMsPerTick = iMsPerTick + ret.bpm = bpm + ret.ppqn = ppqn + ret.total_ticks = total_ticks + ret.iLengthInMs = total_ticks * iMsPerTick + ret.trackList = trackList + return ret + +def TimeStr(ms): + """ Returns a time string """ + s=ms/1000 + m,s=divmod(s,60) + h,m=divmod(m,60) + d,h=divmod(h,24) + if m > 0: + return "%d Min %d Sec" % (m,s) + else: + return "%d Seconds" % (s) + +def mbtFct(mbt, mod): + """ Converts times """ + if type(mbt).__name__=='str' or type(mbt).__name__=='unicode': + mbt = ConvertStrTimeToTuple(mbt) + retType = 'str' + else: + retType = 'int' + + m = mbt[0]+mod + b = mbt[1]+mod + t = mbt[2] + if m < 0: + m = 0 + if b < 0: + b = 0 + if b > 4: + b = 4 + if t < 0: + t = 0 + + if retType == 'str': + return "%d:%d:%d" % (m, b, t) + else: + return (m, b, t) + +def OsWindows(): + """ Tells us whether windows or os x """ + if os.name == 'nt': + return True ; + else: + return False ; + +def MacOffset(): + """ Mac screen coordinates funky on some controls so we finagle a few pixels """ + if not OsWindows(): + return 3 + else: + return 0 + +def SafeJetShutdown(lock, jet): + """ Makes sure we do the jet shutdown properly """ + with lock: + #MAKE SURE WE CLEANUP + #try: jet.Clear_Queue() + #except: pass + + try: jet.eas.StopWave() + except: pass + + try: jet.Shutdown() + except: pass + + jet = None + + +def CreateTempJetFile(org_jet_file): + """ Creates temporary jet file for playback testing """ + dirname = JetDefs.TEMP_JET_DIR + if not os.path.isdir(dirname): + os.mkdir(dirname) + + tmpConfigFile = dirname + FileJustName(org_jet_file.config_file) + FileKillClean(tmpConfigFile) + + jet_file = copy.deepcopy(org_jet_file) + + for tmp in jet_file.segments: + tmp.output = dirname + FileJustName(tmp.output) + + jet_file.config_file = tmpConfigFile + jet_file.config.filename = dirname + FileJustName(jet_file.config.filename) + FileKillClean(jet_file.config.filename) + + jet_file.SaveJetConfig(tmpConfigFile) + jet_file.WriteJetFileFromConfig(tmpConfigFile) + + return jet_file + +def CleanupTempJetFile(jet_file): + """ Cleans up temporary files """ + FileKillClean(jet_file.config.filename) + FileKillClean(jet_file.config_file) + for tmp in jet_file.segments: + FileKillClean(tmp.output) + +def GetNow(): + return time.asctime() + + +if __name__ == '__main__': + """ Tests functions """ + pass + + \ No newline at end of file -- cgit v1.2.3