You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
776 lines
32 KiB
776 lines
32 KiB
"""
|
|
File:
|
|
JetFile.py
|
|
|
|
Contents and purpose:
|
|
Auditions a jet file to simulate interactive music functions
|
|
|
|
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 logging
|
|
import ConfigParser
|
|
import struct
|
|
import os
|
|
import sys
|
|
import midifile
|
|
|
|
from JetUtils import *
|
|
from JetDefs import *
|
|
|
|
VERSION = '0.1'
|
|
|
|
# JET file defines
|
|
JET_HEADER_STRUCT = '<4sl'
|
|
JET_HEADER_TAG = 'JET '
|
|
JET_VERSION = 0x01000000
|
|
|
|
# JET chunk tags
|
|
JET_INFO_CHUNK = 'JINF'
|
|
JET_SMF_CHUNK = 'JSMF'
|
|
JET_DLS_CHUNK = 'JDLS'
|
|
|
|
# JINF defines
|
|
JINF_STRUCT = '<4sl4sl4sl4sl'
|
|
JINF_JET_VERSION = 'JVER'
|
|
JINF_NUM_SMF_CHUNKS = 'SMF#'
|
|
JINF_NUM_DLS_CHUNKS = 'DLS#'
|
|
|
|
# JCOP defines
|
|
JCOP_STRUCT = '<4sl'
|
|
JCOP_CHUNK = 'JCOP'
|
|
|
|
# JAPP defines
|
|
JAPP_STRUCT = '<4sl'
|
|
JAPP_CHUNK = 'JAPP'
|
|
|
|
# config file defines
|
|
OUTPUT_SECTION = 'output'
|
|
OUTPUT_FILENAME = 'filename'
|
|
OUTPUT_COPYRIGHT = 'copyright'
|
|
OUTPUT_APP_DATA = 'app_data'
|
|
OUTPUT_CHASE_CONTROLLERS = 'chase_controllers'
|
|
OUTPUT_OMIT_EMPTY_TRACKS = 'omit_empty_tracks'
|
|
SEGMENT_SECTION = 'segment'
|
|
SEGMENT_FILENAME = 'filename'
|
|
SEGMENT_DLSFILE = 'dlsfile'
|
|
SEGMENT_NAME = 'segname'
|
|
SEGMENT_START = 'start'
|
|
SEGMENT_END = 'end'
|
|
SEGMENT_END_MARKER = 'end_marker'
|
|
SEGMENT_QUANTIZE = 'quantize'
|
|
SEGMENT_OUTPUT = 'output'
|
|
SEGMENT_LENGTH = 'length'
|
|
SEGMENT_DUMP_FILE = 'dump'
|
|
SEGMENT_TRANSPOSE = 'transpose'
|
|
SEGMENT_REPEAT = 'repeat'
|
|
SEGMENT_MUTE_FLAGS = 'mute_flags'
|
|
LIBRARY_SECTION = 'libraries'
|
|
LIBRARY_FILENAME = 'lib'
|
|
CLIP_PREFIX = 'clip'
|
|
APP_PREFIX = 'app'
|
|
|
|
# JET events
|
|
JET_EVENT_MARKER = 102
|
|
JET_MARKER_LOOP_END = 0
|
|
JET_EVENT_TRIGGER_CLIP = 103
|
|
|
|
class JetSegment (object):
|
|
""" Class to hold segments """
|
|
def __init__ (self, segname, filename, start=None, end=None, length=None, output=None, quantize=None, jetevents=[], dlsfile=None, dump_file=None, transpose=0, repeat=0, mute_flags=0):
|
|
self.segname = segname
|
|
self.filename = filename
|
|
self.dlsfile = dlsfile
|
|
self.start = start
|
|
self.end = end
|
|
self.length = length
|
|
self.output = output
|
|
self.quantize = quantize
|
|
self.dump_file = dump_file
|
|
self.jetevents = jetevents
|
|
#API FIELDS FOR UI
|
|
self.transpose = transpose
|
|
self.repeat = repeat
|
|
self.mute_flags = mute_flags
|
|
|
|
class JetEvent (object):
|
|
""" Class to hold events """
|
|
def __init__(self, event_name, event_type, event_id, track_num, channel_num, event_start, event_end):
|
|
self.event_name = event_name
|
|
self.event_type = event_type
|
|
self.event_id = event_id
|
|
self.track_num = track_num
|
|
self.channel_num = channel_num
|
|
self.event_start = event_start
|
|
self.event_end = event_end
|
|
|
|
class JetFileException (Exception):
|
|
""" Exceptions class """
|
|
def __init__ (self, msg):
|
|
self.msg = msg
|
|
def __str__ (self):
|
|
return self.msg
|
|
|
|
class JetSegmentFile (midifile.MIDIFile):
|
|
def ConvertMusicTimeToTicks (self, s):
|
|
measures, beats, ticks = s.split(':',3)
|
|
return self.ConvertToTicks(int(measures), int(beats), int(ticks))
|
|
|
|
def ExtractEvents (self, start, end, length, quantize, chase_controllers):
|
|
if (start is None) and (end is None) and (length is None):
|
|
logging.debug('ExtractEvents: No change')
|
|
return
|
|
|
|
if start is not None:
|
|
start = self.ConvertMusicTimeToTicks(start)
|
|
else:
|
|
start = 0
|
|
if end is not None:
|
|
end = self.ConvertMusicTimeToTicks(end)
|
|
elif length is not None:
|
|
length = self.ConvertMusicTimeToTicks(length)
|
|
end = start + length
|
|
|
|
if quantize is not None:
|
|
quantize = int(quantize)
|
|
else:
|
|
quantize = 0
|
|
|
|
self.Trim(start, end, quantize, chase_controllers=chase_controllers)
|
|
#self.DumpTracks()
|
|
|
|
def SyncClips (self):
|
|
"""Add controller events to the start of a clip to keep it synced."""
|
|
values = None
|
|
last_seq = 0
|
|
for track in self.tracks:
|
|
for event in track.events:
|
|
|
|
# find start of clip and chase events from last save point
|
|
if (event.msg_type == midifile.CONTROL_CHANGE) and \
|
|
(event.controller == JET_EVENT_TRIGGER_CLIP) and \
|
|
((event.value & 0x40) == 0x40):
|
|
logging.debug('Syncing clip at %d ticks' % event.ticks)
|
|
values = track.events.ChaseControllers(event.seq, last_seq, values)
|
|
|
|
#BTH; Seems to fix chase controller bug when multiple clips within segment
|
|
#last_seq = event.seq
|
|
|
|
# generate event list from default values
|
|
clip_events = values.GenerateEventList(event.ticks)
|
|
|
|
#for evt in clip_events:
|
|
# logging.info(evt)
|
|
|
|
track.events.InsertEvents(clip_events, event.seq + 1)
|
|
|
|
def AddJetEvents (self, jetevents):
|
|
for jet_event in jetevents:
|
|
if jet_event.event_type == JetDefs.E_CLIP:
|
|
#DumpEvent(jet_event)
|
|
|
|
# sanity check
|
|
if jet_event.track_num >= len(self.tracks):
|
|
raise JetFileException('Track number %d of out of range for clip' % jet_event.track_num)
|
|
if jet_event.channel_num > 15:
|
|
raise JetFileException('Channel number %d of out of range for clip' % jet_event.channel_num)
|
|
if jet_event.event_id > 63:
|
|
raise JetFileException('event_id %d of out of range for clip' % jet_event.event_id)
|
|
|
|
logging.debug('Adding trigger event for clip %d @ %s and %s' % (jet_event.event_id, jet_event.event_start, jet_event.event_end))
|
|
|
|
events = midifile.EventList()
|
|
events.append(midifile.ControlChangeEvent(
|
|
self.ConvertMusicTimeToTicks(jet_event.event_start),
|
|
0,
|
|
jet_event.channel_num,
|
|
JET_EVENT_TRIGGER_CLIP,
|
|
jet_event.event_id | 0x40))
|
|
|
|
events.append(midifile.ControlChangeEvent(
|
|
self.ConvertMusicTimeToTicks(jet_event.event_end),
|
|
sys.maxint,
|
|
jet_event.channel_num,
|
|
JET_EVENT_TRIGGER_CLIP,
|
|
jet_event.event_id))
|
|
|
|
# merge trigger events
|
|
self.tracks[jet_event.track_num].events.MergeEvents(events)
|
|
|
|
elif jet_event.event_type == JetDefs.E_EOS:
|
|
if jet_event.track_num >= len(self.tracks):
|
|
raise JetFileException('Track number %d of out of range for end marker' % jet_event.track_num)
|
|
if jet_event.channel_num > 15:
|
|
raise JetFileException('Channel number %d of out of range for end marker' % jet_event.channel_num)
|
|
|
|
events = midifile.EventList()
|
|
logging.debug('Adding end marker at %s' % jet_event.event_start)
|
|
events.append(midifile.ControlChangeEvent(
|
|
self.ConvertMusicTimeToTicks(jet_event.event_start),
|
|
0,
|
|
jet_event.channel_num,
|
|
JET_EVENT_MARKER,
|
|
JET_MARKER_LOOP_END))
|
|
self.tracks[jet_event.track_num].events.MergeEvents(events)
|
|
|
|
elif jet_event.event_type == JetDefs.E_APP:
|
|
if jet_event.track_num >= len(self.tracks):
|
|
raise JetFileException('Track number %d of out of range for app marker' % jet_event.track_num)
|
|
if jet_event.channel_num > 15:
|
|
raise JetFileException('Channel number %d of out of range for app marker' % jet_event.channel_num)
|
|
if jet_event.event_id > 83 or jet_event.event_id < 80:
|
|
raise JetFileException('EventID %d out of range for application controller' % jet_event.event_id)
|
|
|
|
events = midifile.EventList()
|
|
logging.debug('Adding application controller at %s' % jet_event.event_start)
|
|
events.append(midifile.ControlChangeEvent(
|
|
self.ConvertMusicTimeToTicks(jet_event.event_start),
|
|
0,
|
|
jet_event.channel_num,
|
|
jet_event.event_id,
|
|
jet_event.event_id))
|
|
self.tracks[jet_event.track_num].events.MergeEvents(events)
|
|
|
|
class JetFile (object):
|
|
"""Write a JET file based on a configuration file."""
|
|
def __init__ (self, config_file, options):
|
|
self.config_file = config_file
|
|
self.config = config = ConfigParser.ConfigParser()
|
|
if self.config_file == "":
|
|
self.InitializeConfig(JetDefs.UNTITLED_FILE)
|
|
if not FileExists(self.config_file):
|
|
self.InitializeConfig(self.config_file)
|
|
|
|
config.read(self.config_file)
|
|
self.ParseConfig(options)
|
|
|
|
def DumpConfig (self):
|
|
"""Drump configuration to log file."""
|
|
# dump configuration
|
|
config = self.config
|
|
for section in config.sections():
|
|
logging.debug('[%s]' % section)
|
|
for option, value in config.items(section):
|
|
logging.debug('%s: %s' % (option, value))
|
|
|
|
def ParseConfig (self, options):
|
|
"""Validate the configuration."""
|
|
# check for output name
|
|
config = self.config
|
|
if config.has_option(OUTPUT_SECTION, OUTPUT_FILENAME):
|
|
config.filename = config.get(OUTPUT_SECTION, OUTPUT_FILENAME)
|
|
else:
|
|
raise JetFileException('No output filename in configuration file')
|
|
if config.filename == '' or config.filename == None:
|
|
config.filename = FileJustRoot(self.config_file) + ".JET"
|
|
config.chase_controllers = True
|
|
if config.has_option(OUTPUT_SECTION, OUTPUT_CHASE_CONTROLLERS):
|
|
try:
|
|
config.chase_controllers = config.getboolean(OUTPUT_SECTION, OUTPUT_CHASE_CONTROLLERS)
|
|
except:
|
|
pass
|
|
|
|
config.delete_empty_tracks = False
|
|
if config.has_option(OUTPUT_SECTION, OUTPUT_OMIT_EMPTY_TRACKS):
|
|
try:
|
|
config.delete_empty_tracks = config.getboolean(OUTPUT_SECTION, OUTPUT_OMIT_EMPTY_TRACKS)
|
|
except:
|
|
pass
|
|
|
|
config.copyright = None
|
|
if config.has_option(OUTPUT_SECTION, OUTPUT_COPYRIGHT):
|
|
config.copyright = config.get(OUTPUT_SECTION, OUTPUT_COPYRIGHT)
|
|
|
|
config.app_data = None
|
|
if config.has_option(OUTPUT_SECTION, OUTPUT_APP_DATA):
|
|
config.app_data = config.get(OUTPUT_SECTION, OUTPUT_APP_DATA)
|
|
|
|
# count segments
|
|
segments = []
|
|
seg_num = 0
|
|
while 1:
|
|
|
|
# check for segment section
|
|
segment_name = SEGMENT_SECTION + str(seg_num)
|
|
if not config.has_section(segment_name):
|
|
break
|
|
|
|
# initialize some parameters
|
|
start = end = length = output = end_marker = dlsfile = dump_file = None
|
|
transpose = repeat = mute_flags = 0
|
|
jetevents = []
|
|
|
|
# get the segment parameters
|
|
segname = config.get(segment_name, SEGMENT_NAME)
|
|
filename = config.get(segment_name, SEGMENT_FILENAME)
|
|
if config.has_option(segment_name, SEGMENT_DLSFILE):
|
|
dlsfile = config.get(segment_name, SEGMENT_DLSFILE)
|
|
if config.has_option(segment_name, SEGMENT_START):
|
|
start = config.get(segment_name, SEGMENT_START)
|
|
if config.has_option(segment_name, SEGMENT_END):
|
|
end = config.get(segment_name, SEGMENT_END)
|
|
if config.has_option(segment_name, SEGMENT_LENGTH):
|
|
length = config.get(segment_name, SEGMENT_LENGTH)
|
|
if config.has_option(segment_name, SEGMENT_OUTPUT):
|
|
output = config.get(segment_name, SEGMENT_OUTPUT)
|
|
if config.has_option(segment_name, SEGMENT_QUANTIZE):
|
|
quantize = config.get(segment_name, SEGMENT_QUANTIZE)
|
|
if config.has_option(segment_name, SEGMENT_DUMP_FILE):
|
|
dump_file = config.get(segment_name, SEGMENT_DUMP_FILE)
|
|
#API FIELDS
|
|
if config.has_option(segment_name, SEGMENT_TRANSPOSE):
|
|
transpose = config.get(segment_name, SEGMENT_TRANSPOSE)
|
|
if config.has_option(segment_name, SEGMENT_REPEAT):
|
|
repeat = config.get(segment_name, SEGMENT_REPEAT)
|
|
if config.has_option(segment_name, SEGMENT_MUTE_FLAGS):
|
|
mute_flags = config.get(segment_name, SEGMENT_MUTE_FLAGS)
|
|
|
|
if config.has_option(segment_name, SEGMENT_END_MARKER):
|
|
end_marker = config.get(segment_name, SEGMENT_END_MARKER)
|
|
track_num, channel_num, event_time = end_marker.split(',',2)
|
|
#jetevents.append((JetDefs.E_EOS, 0, int(track_num), int(channel_num), event_time, ''))
|
|
jetevents.append(JetEvent(JetDefs.E_EOS, JetDefs.E_EOS, 0, int(track_num), int(channel_num), event_time, event_time))
|
|
|
|
# check for jetevents
|
|
for jetevent, location in config.items(segment_name):
|
|
if jetevent.startswith(CLIP_PREFIX):
|
|
event_name, event_id, track_num, channel_num, event_start, event_end = location.split(',', 5)
|
|
jetevents.append(JetEvent(event_name, JetDefs.E_CLIP, int(event_id), int(track_num), int(channel_num), event_start, event_end))
|
|
|
|
# check for appevents
|
|
for jetevent, location in config.items(segment_name):
|
|
if jetevent.startswith(APP_PREFIX):
|
|
event_name, event_id, track_num, channel_num, event_start, event_end = location.split(',', 5)
|
|
jetevents.append(JetEvent(event_name, JetDefs.E_APP, int(event_id), int(track_num), int(channel_num), event_start, event_end))
|
|
|
|
segments.append(JetSegment(segname, filename, start, end, length, output, quantize, jetevents, dlsfile, dump_file, int(transpose), int(repeat), int(mute_flags)))
|
|
seg_num += 1
|
|
|
|
self.segments = segments
|
|
if not len(segments):
|
|
#TODO: Check for segments when writing
|
|
#raise JetFileException('No segments defined in configuration file')
|
|
pass
|
|
|
|
# count libraries
|
|
libraries = []
|
|
lib_num = 0
|
|
while 1:
|
|
library_name = LIBRARY_FILENAME + str(lib_num)
|
|
if not config.has_option(LIBRARY_SECTION, library_name):
|
|
break
|
|
libraries.append(config.get(LIBRARY_SECTION, library_name))
|
|
lib_num += 1
|
|
self.libraries = libraries
|
|
|
|
def WriteJetFileFromConfig (self, options):
|
|
"""Write JET file from config file."""
|
|
|
|
# open the output file and write the header
|
|
output_file = open(self.config.filename, 'wb')
|
|
jet_header = struct.pack(JET_HEADER_STRUCT, JET_HEADER_TAG, 0)
|
|
output_file.write(jet_header)
|
|
|
|
# write the JINF chunk
|
|
jet_info = struct.pack(JINF_STRUCT,
|
|
JET_INFO_CHUNK, struct.calcsize(JINF_STRUCT) - 8,
|
|
JINF_JET_VERSION, JET_VERSION,
|
|
JINF_NUM_SMF_CHUNKS, len(self.segments),
|
|
JINF_NUM_DLS_CHUNKS, len(self.libraries))
|
|
output_file.write(jet_info)
|
|
|
|
# write the JCOP chunk (if any)
|
|
if self.config.copyright is not None:
|
|
size = len(self.config.copyright) + 1
|
|
if size & 1:
|
|
size += 1
|
|
extra_byte = True
|
|
else:
|
|
extra_byte = False
|
|
jet_copyright = struct.pack(JCOP_STRUCT, JCOP_CHUNK, size)
|
|
output_file.write(jet_copyright)
|
|
output_file.write(self.config.copyright)
|
|
output_file.write(chr(0))
|
|
if extra_byte:
|
|
output_file.write(chr(0))
|
|
|
|
# write the app data chunk (if any)
|
|
if self.config.app_data is not None:
|
|
size = os.path.getsize(self.config.app_data)
|
|
if size & 1:
|
|
size += 1
|
|
extra_byte = True
|
|
else:
|
|
extra_byte = False
|
|
jet_app_data = struct.pack(JAPP_STRUCT, JAPP_CHUNK, size)
|
|
output_file.write(jet_app_data)
|
|
with open(self.config.app_data, 'rb') as f:
|
|
output_file.write(f.read())
|
|
if extra_byte:
|
|
output_file.write(chr(0))
|
|
|
|
# copy the MIDI segments
|
|
seg_num = 0
|
|
for segment in self.segments:
|
|
logging.debug('Writing segment %d' % seg_num)
|
|
|
|
# open SMF file and read it
|
|
jet_segfile = JetSegmentFile(segment.filename, 'rb')
|
|
jet_segfile.ReadFromStream()
|
|
|
|
# insert events
|
|
jet_segfile.AddJetEvents(segment.jetevents)
|
|
|
|
# trim to length specified in config file
|
|
jet_segfile.ExtractEvents(segment.start, segment.end, segment.length, segment.quantize, self.config.chase_controllers)
|
|
|
|
# chase controller events and fix them
|
|
if self.config.chase_controllers:
|
|
jet_segfile.SyncClips()
|
|
|
|
# delete empty tracks
|
|
if self.config.delete_empty_tracks:
|
|
jet_segfile.DeleteEmptyTracks()
|
|
|
|
# write separate output file if requested
|
|
if segment.output is not None:
|
|
jet_segfile.SaveAs(segment.output)
|
|
|
|
# write dump file
|
|
if segment.dump_file is not None:
|
|
with open(segment.dump_file, 'w') as f:
|
|
jet_segfile.DumpTracks(f)
|
|
|
|
# write the segment header
|
|
header_pos = output_file.tell()
|
|
smf_header = struct.pack(JET_HEADER_STRUCT, JET_SMF_CHUNK, 0)
|
|
output_file.write(smf_header)
|
|
start_pos = output_file.tell()
|
|
|
|
# write SMF file to output file
|
|
jet_segfile.Write(output_file, offset=start_pos)
|
|
jet_segfile.close()
|
|
|
|
# return to segment header and write actual size
|
|
end_pos = output_file.tell()
|
|
file_size = end_pos - start_pos
|
|
if file_size & 1:
|
|
file_size += 1
|
|
end_pos += 1
|
|
output_file.seek(header_pos, 0)
|
|
smf_header = struct.pack(JET_HEADER_STRUCT, JET_SMF_CHUNK, file_size)
|
|
output_file.write(smf_header)
|
|
output_file.seek(end_pos, 0)
|
|
|
|
seg_num += 1
|
|
|
|
# copy the DLS segments
|
|
for library in self.libraries:
|
|
if FileExists(library):
|
|
# open SMF file and get size
|
|
lib_file = (open(library,'rb'))
|
|
lib_file.seek(0,2)
|
|
file_size = lib_file.tell()
|
|
lib_file.seek(0)
|
|
|
|
# write the library header
|
|
dls_header = struct.pack(JET_HEADER_STRUCT, JET_DLS_CHUNK, file_size)
|
|
output_file.write(dls_header)
|
|
|
|
# copy DLS file to output file
|
|
output_file.write(lib_file.read())
|
|
lib_file.close()
|
|
|
|
# write the header with the read data size
|
|
file_size = output_file.tell()
|
|
output_file.seek(0)
|
|
jet_header = struct.pack(JET_HEADER_STRUCT, JET_HEADER_TAG, file_size - struct.calcsize(JET_HEADER_STRUCT))
|
|
output_file.write(jet_header)
|
|
output_file.close()
|
|
|
|
def GetMidiFiles(self):
|
|
""" Gets a list of midifiles """
|
|
midiFiles = []
|
|
for segment in self.segments:
|
|
if segment.filename not in midiFiles:
|
|
midiFiles.append(segment.filename)
|
|
return midiFiles
|
|
|
|
def GetLibraries(self):
|
|
""" Gets the libraries """
|
|
return self.libraries
|
|
|
|
def GetEvents(self, segName):
|
|
""" Gets the events for a segment """
|
|
for segment in self.segments:
|
|
if segment.segname == segName:
|
|
return segment.jetevents
|
|
return None
|
|
|
|
def GetEvent(self, segName, eventName):
|
|
""" Gets a single event from a segment """
|
|
for segment in self.segments:
|
|
if segment.segname == segName:
|
|
for event in segment.jetevents:
|
|
if event.event_name == eventName:
|
|
return event
|
|
return None
|
|
|
|
def AddEvent(self, segname, event_name, event_type, event_id, track_num, channel_num, event_start, event_end):
|
|
""" Adds an event """
|
|
for segment in self.segments:
|
|
if segment.segname == segname:
|
|
segment.jetevents.append(JetEvent(event_name, event_type, int(event_id), int(track_num), int(channel_num), event_start, event_end))
|
|
|
|
def ReplaceEvents(self, segname, newEvents):
|
|
""" Replaces all events """
|
|
for segment in self.segments:
|
|
if segment.segname == segname:
|
|
segment.jetevents = newEvents
|
|
return segment
|
|
|
|
def UpdateEvent(self, segname, orgeventname, event_name, event_type, event_id, track_num, channel_num, event_start, event_end):
|
|
""" Updates an event """
|
|
for segment in self.segments:
|
|
if segment.segname == segname:
|
|
for jetevent in segment.jetevents:
|
|
if jetevent.event_name == orgeventname:
|
|
jetevent.event_name = event_name
|
|
jetevent.event_type = event_type
|
|
jetevent.event_id = event_id
|
|
jetevent.track_num = track_num
|
|
jetevent.channel_num = channel_num
|
|
jetevent.event_start = event_start
|
|
jetevent.event_end = event_end
|
|
|
|
def DeleteSegmentsMatchingPrefix(self, prefix):
|
|
""" Deletes all segments matching name """
|
|
iOnce = True
|
|
iAgain = False
|
|
while(iOnce or iAgain):
|
|
iOnce = False
|
|
iAgain = False
|
|
for segment in self.segments:
|
|
if segment.segname[0:len(prefix)].upper() == prefix.upper():
|
|
self.segments.remove(segment)
|
|
iAgain = True
|
|
|
|
def DeleteEvent(self, segname, event_name):
|
|
""" Deletes an event """
|
|
for segment in self.segments:
|
|
if segment.segname == segname:
|
|
for jetevent in segment.jetevents:
|
|
if jetevent.event_name == event_name:
|
|
segment.jetevents.remove(jetevent)
|
|
|
|
def DeleteEventsMatchingPrefix(self, segname, prefix):
|
|
""" Deletes all events matching name """
|
|
for segment in self.segments:
|
|
if segment.segname == segname:
|
|
iOnce = True
|
|
iAgain = False
|
|
while(iOnce or iAgain):
|
|
iOnce = False
|
|
iAgain = False
|
|
for jetevent in segment.jetevents:
|
|
if jetevent.event_name[0:len(prefix)].upper() == prefix.upper():
|
|
segment.jetevents.remove(jetevent)
|
|
iAgain = True
|
|
|
|
def MoveEvent(self, segname, movename, event_start, event_end):
|
|
""" Move an event """
|
|
for segment in self.segments:
|
|
if segment.segname == segname:
|
|
for jetevent in segment.jetevents:
|
|
if jetevent.event_name == movename:
|
|
jetevent.event_start = event_start
|
|
jetevent.event_end = event_end
|
|
return
|
|
|
|
def GetSegments(self):
|
|
""" Gets all segments """
|
|
return self.segments
|
|
|
|
def GetSegment(self, segName):
|
|
""" Gets one segment by name """
|
|
for segment in self.segments:
|
|
if segment.segname == segName:
|
|
return segment
|
|
return None
|
|
|
|
def AddSegment(self, segname, filename, start, end, length, output, quantize, jetevents, dlsfile, dump_file, transpose, repeat, mute_flags):
|
|
""" Adds a segment """
|
|
if length == JetDefs.MBT_ZEROSTR:
|
|
length = None
|
|
if end == JetDefs.MBT_ZEROSTR:
|
|
end = None
|
|
self.segments.append(JetSegment(segname, filename, start, end, length, output, quantize, jetevents, dlsfile, dump_file, transpose, repeat, mute_flags))
|
|
|
|
def UpdateSegment(self, orgsegname, segname, filename, start, end, length, output, quantize, jetevents, dlsfile, dump_file, transpose, repeat, mute_flags):
|
|
""" Updates a segment """
|
|
if length == JetDefs.MBT_ZEROSTR:
|
|
length = None
|
|
if end == JetDefs.MBT_ZEROSTR:
|
|
end = None
|
|
for segment in self.segments:
|
|
if segment.segname == orgsegname:
|
|
segment.segname = segname
|
|
segment.filename = filename
|
|
segment.start = start
|
|
segment.end = end
|
|
segment.length = length
|
|
segment.output = output
|
|
segment.quantize = quantize
|
|
segment.dlsfile = dlsfile
|
|
segment.transpose = transpose
|
|
segment.repeat = repeat
|
|
segment.mute_flags = mute_flags
|
|
|
|
def MoveSegment(self, segname, start, end):
|
|
""" Moves a segment """
|
|
for segment in self.segments:
|
|
if segment.segname == segname:
|
|
segment.start = start
|
|
segment.end = end
|
|
return
|
|
|
|
def DeleteSegment(self, segname):
|
|
""" Deletes a segment """
|
|
for segment in self.segments:
|
|
if segment.segname == segname:
|
|
self.segments.remove(segment)
|
|
|
|
def SaveJetConfig(self, configFile):
|
|
""" Saves the jet config file """
|
|
if self.config.filename == '' or self.config.filename == None:
|
|
self.config.filename = FileJustRoot(configFile) + ".JET"
|
|
config = ConfigParser.ConfigParser()
|
|
config.add_section(OUTPUT_SECTION)
|
|
config.set(OUTPUT_SECTION, OUTPUT_FILENAME, self.config.filename)
|
|
config.set(OUTPUT_SECTION, OUTPUT_CHASE_CONTROLLERS, self.config.chase_controllers)
|
|
config.set(OUTPUT_SECTION, OUTPUT_OMIT_EMPTY_TRACKS, self.config.delete_empty_tracks)
|
|
if self.config.copyright is not None:
|
|
config.set(OUTPUT_SECTION, OUTPUT_COPYRIGHT, self.config.copyright)
|
|
if self.config.app_data is not None:
|
|
config.set(OUTPUT_SECTION, OUTPUT_APP_DATA, self.config.app_data)
|
|
|
|
self.libraries = []
|
|
seg_num = 0
|
|
for segment in self.segments:
|
|
segment_name = SEGMENT_SECTION + str(seg_num)
|
|
config.add_section(segment_name)
|
|
config.set(segment_name, SEGMENT_NAME, segment.segname)
|
|
config.set(segment_name, SEGMENT_FILENAME, segment.filename)
|
|
|
|
config.set(segment_name, SEGMENT_DLSFILE, segment.dlsfile)
|
|
if FileExists(segment.dlsfile):
|
|
if not segment.dlsfile in self.libraries:
|
|
self.libraries.append(segment.dlsfile)
|
|
config.set(segment_name, SEGMENT_START, segment.start)
|
|
if segment.end > JetDefs.MBT_ZEROSTR and len(segment.end) > 0:
|
|
config.set(segment_name, SEGMENT_END, segment.end)
|
|
if segment.length > JetDefs.MBT_ZEROSTR and len(segment.length) > 0:
|
|
config.set(segment_name, SEGMENT_LENGTH, segment.length)
|
|
config.set(segment_name, SEGMENT_OUTPUT, segment.output)
|
|
config.set(segment_name, SEGMENT_QUANTIZE, segment.quantize)
|
|
if segment.dump_file is not None:
|
|
config.set(segment_name, SEGMENT_DUMP_FILE, segment.dump_file)
|
|
config.set(segment_name, SEGMENT_TRANSPOSE, segment.transpose)
|
|
config.set(segment_name, SEGMENT_REPEAT, segment.repeat)
|
|
config.set(segment_name, SEGMENT_MUTE_FLAGS, segment.mute_flags)
|
|
|
|
clip_num = 0
|
|
app_num = 0
|
|
for jet_event in segment.jetevents:
|
|
if jet_event.event_type == JetDefs.E_CLIP:
|
|
clip_name = CLIP_PREFIX + str(clip_num)
|
|
s = "%s,%s,%s,%s,%s,%s" % (jet_event.event_name, jet_event.event_id, jet_event.track_num, jet_event.channel_num, jet_event.event_start, jet_event.event_end)
|
|
config.set(segment_name, clip_name, s)
|
|
clip_num += 1
|
|
elif jet_event.event_type == JetDefs.E_APP:
|
|
app_name = APP_PREFIX + str(app_num)
|
|
s = "%s,%s,%s,%s,%s,%s" % (jet_event.event_name, jet_event.event_id, jet_event.track_num, jet_event.channel_num, jet_event.event_start, jet_event.event_end)
|
|
config.set(segment_name, app_name, s)
|
|
app_num += 1
|
|
elif jet_event.event_type == JetDefs.E_EOS:
|
|
s = "%s,%s,%s" % (jet_event.track_num, jet_event.channel_num, jet_event.event_start)
|
|
config.set(segment_name, SEGMENT_END_MARKER, s)
|
|
|
|
seg_num += 1
|
|
|
|
lib_num = 0
|
|
config.add_section(LIBRARY_SECTION)
|
|
for library in self.libraries:
|
|
library_name = LIBRARY_FILENAME + str(lib_num)
|
|
config.set(LIBRARY_SECTION, library_name, library)
|
|
lib_num += 1
|
|
|
|
FileKillClean(configFile)
|
|
cfgfile = open(configFile,'w')
|
|
config.write(cfgfile)
|
|
cfgfile.close()
|
|
|
|
def InitializeConfig(self, configFile):
|
|
""" Initializes the values for an empty flag """
|
|
self.config.filename = FileJustRoot(configFile) + ".JET"
|
|
self.config.chase_controllers = True
|
|
self.config.delete_empty_tracks = False
|
|
self.config.copyright = None
|
|
self.config.app_data = None
|
|
self.segments = []
|
|
self.libraries = []
|
|
self.config_file = configFile
|
|
self.SaveJetConfig(configFile)
|
|
|
|
|
|
|
|
#---------------------------------------------------------------
|
|
# main
|
|
#---------------------------------------------------------------
|
|
if __name__ == '__main__':
|
|
sys = __import__('sys')
|
|
optparse = __import__('optparse')
|
|
|
|
# parse command line options
|
|
parser = optparse.OptionParser(version=VERSION)
|
|
parser.set_defaults(log_level=logging.INFO, log_file=None)
|
|
parser.add_option('-d', '--debug', action="store_const", const=logging.DEBUG, dest='log_level', help='Enable debug output')
|
|
parser.add_option('-l', '--log_file', dest='log_file', help='Write debug output to log file')
|
|
(options, args) = parser.parse_args()
|
|
|
|
# get master logger
|
|
logger = logging.getLogger('')
|
|
logger.setLevel(options.log_level)
|
|
|
|
# create console logger
|
|
console_logger = logging.StreamHandler()
|
|
console_logger.setFormatter(logging.Formatter('%(message)s'))
|
|
logger.addHandler(console_logger)
|
|
|
|
# create rotating file logger
|
|
if options.log_file is not None:
|
|
file_logger = logging.FileHandler(options.log_file, 'w')
|
|
file_logger.setFormatter(logging.Formatter('%(message)s'))
|
|
logger.addHandler(file_logger)
|
|
|
|
# process files
|
|
for arg in args:
|
|
print arg
|
|
jet_file = JetFile(arg, options)
|
|
jet_file.WriteJetFileFromConfig(options)
|
|
|