1 """ 2 File: 3 JetFile.py 4 5 Contents and purpose: 6 Auditions a jet file to simulate interactive music functions 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 logging 26 import ConfigParser 27 import struct 28 import os 29 import sys 30 import midifile 31 32 from JetUtils import * 33 from JetDefs import * 34 35 VERSION = '0.1' 36 37 # JET file defines 38 JET_HEADER_STRUCT = '<4sl' 39 JET_HEADER_TAG = 'JET ' 40 JET_VERSION = 0x01000000 41 42 # JET chunk tags 43 JET_INFO_CHUNK = 'JINF' 44 JET_SMF_CHUNK = 'JSMF' 45 JET_DLS_CHUNK = 'JDLS' 46 47 # JINF defines 48 JINF_STRUCT = '<4sl4sl4sl4sl' 49 JINF_JET_VERSION = 'JVER' 50 JINF_NUM_SMF_CHUNKS = 'SMF#' 51 JINF_NUM_DLS_CHUNKS = 'DLS#' 52 53 # JCOP defines 54 JCOP_STRUCT = '<4sl' 55 JCOP_CHUNK = 'JCOP' 56 57 # JAPP defines 58 JAPP_STRUCT = '<4sl' 59 JAPP_CHUNK = 'JAPP' 60 61 # config file defines 62 OUTPUT_SECTION = 'output' 63 OUTPUT_FILENAME = 'filename' 64 OUTPUT_COPYRIGHT = 'copyright' 65 OUTPUT_APP_DATA = 'app_data' 66 OUTPUT_CHASE_CONTROLLERS = 'chase_controllers' 67 OUTPUT_OMIT_EMPTY_TRACKS = 'omit_empty_tracks' 68 SEGMENT_SECTION = 'segment' 69 SEGMENT_FILENAME = 'filename' 70 SEGMENT_DLSFILE = 'dlsfile' 71 SEGMENT_NAME = 'segname' 72 SEGMENT_START = 'start' 73 SEGMENT_END = 'end' 74 SEGMENT_END_MARKER = 'end_marker' 75 SEGMENT_QUANTIZE = 'quantize' 76 SEGMENT_OUTPUT = 'output' 77 SEGMENT_LENGTH = 'length' 78 SEGMENT_DUMP_FILE = 'dump' 79 SEGMENT_TRANSPOSE = 'transpose' 80 SEGMENT_REPEAT = 'repeat' 81 SEGMENT_MUTE_FLAGS = 'mute_flags' 82 LIBRARY_SECTION = 'libraries' 83 LIBRARY_FILENAME = 'lib' 84 CLIP_PREFIX = 'clip' 85 APP_PREFIX = 'app' 86 87 # JET events 88 JET_EVENT_MARKER = 102 89 JET_MARKER_LOOP_END = 0 90 JET_EVENT_TRIGGER_CLIP = 103 91 92 class JetSegment (object): 93 """ Class to hold segments """ 94 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): 95 self.segname = segname 96 self.filename = filename 97 self.dlsfile = dlsfile 98 self.start = start 99 self.end = end 100 self.length = length 101 self.output = output 102 self.quantize = quantize 103 self.dump_file = dump_file 104 self.jetevents = jetevents 105 #API FIELDS FOR UI 106 self.transpose = transpose 107 self.repeat = repeat 108 self.mute_flags = mute_flags 109 110 class JetEvent (object): 111 """ Class to hold events """ 112 def __init__(self, event_name, event_type, event_id, track_num, channel_num, event_start, event_end): 113 self.event_name = event_name 114 self.event_type = event_type 115 self.event_id = event_id 116 self.track_num = track_num 117 self.channel_num = channel_num 118 self.event_start = event_start 119 self.event_end = event_end 120 121 class JetFileException (Exception): 122 """ Exceptions class """ 123 def __init__ (self, msg): 124 self.msg = msg 125 def __str__ (self): 126 return self.msg 127 128 class JetSegmentFile (midifile.MIDIFile): 129 def ConvertMusicTimeToTicks (self, s): 130 measures, beats, ticks = s.split(':',3) 131 return self.ConvertToTicks(int(measures), int(beats), int(ticks)) 132 133 def ExtractEvents (self, start, end, length, quantize, chase_controllers): 134 if (start is None) and (end is None) and (length is None): 135 logging.debug('ExtractEvents: No change') 136 return 137 138 if start is not None: 139 start = self.ConvertMusicTimeToTicks(start) 140 else: 141 start = 0 142 if end is not None: 143 end = self.ConvertMusicTimeToTicks(end) 144 elif length is not None: 145 length = self.ConvertMusicTimeToTicks(length) 146 end = start + length 147 148 if quantize is not None: 149 quantize = int(quantize) 150 else: 151 quantize = 0 152 153 self.Trim(start, end, quantize, chase_controllers=chase_controllers) 154 #self.DumpTracks() 155 156 def SyncClips (self): 157 """Add controller events to the start of a clip to keep it synced.""" 158 values = None 159 last_seq = 0 160 for track in self.tracks: 161 for event in track.events: 162 163 # find start of clip and chase events from last save point 164 if (event.msg_type == midifile.CONTROL_CHANGE) and \ 165 (event.controller == JET_EVENT_TRIGGER_CLIP) and \ 166 ((event.value & 0x40) == 0x40): 167 logging.debug('Syncing clip at %d ticks' % event.ticks) 168 values = track.events.ChaseControllers(event.seq, last_seq, values) 169 170 #BTH; Seems to fix chase controller bug when multiple clips within segment 171 #last_seq = event.seq 172 173 # generate event list from default values 174 clip_events = values.GenerateEventList(event.ticks) 175 176 #for evt in clip_events: 177 # logging.info(evt) 178 179 track.events.InsertEvents(clip_events, event.seq + 1) 180 181 def AddJetEvents (self, jetevents): 182 for jet_event in jetevents: 183 if jet_event.event_type == JetDefs.E_CLIP: 184 #DumpEvent(jet_event) 185 186 # sanity check 187 if jet_event.track_num >= len(self.tracks): 188 raise JetFileException('Track number %d of out of range for clip' % jet_event.track_num) 189 if jet_event.channel_num > 15: 190 raise JetFileException('Channel number %d of out of range for clip' % jet_event.channel_num) 191 if jet_event.event_id > 63: 192 raise JetFileException('event_id %d of out of range for clip' % jet_event.event_id) 193 194 logging.debug('Adding trigger event for clip %d @ %s and %s' % (jet_event.event_id, jet_event.event_start, jet_event.event_end)) 195 196 events = midifile.EventList() 197 events.append(midifile.ControlChangeEvent( 198 self.ConvertMusicTimeToTicks(jet_event.event_start), 199 0, 200 jet_event.channel_num, 201 JET_EVENT_TRIGGER_CLIP, 202 jet_event.event_id | 0x40)) 203 204 events.append(midifile.ControlChangeEvent( 205 self.ConvertMusicTimeToTicks(jet_event.event_end), 206 sys.maxint, 207 jet_event.channel_num, 208 JET_EVENT_TRIGGER_CLIP, 209 jet_event.event_id)) 210 211 # merge trigger events 212 self.tracks[jet_event.track_num].events.MergeEvents(events) 213 214 elif jet_event.event_type == JetDefs.E_EOS: 215 if jet_event.track_num >= len(self.tracks): 216 raise JetFileException('Track number %d of out of range for end marker' % jet_event.track_num) 217 if jet_event.channel_num > 15: 218 raise JetFileException('Channel number %d of out of range for end marker' % jet_event.channel_num) 219 220 events = midifile.EventList() 221 logging.debug('Adding end marker at %s' % jet_event.event_start) 222 events.append(midifile.ControlChangeEvent( 223 self.ConvertMusicTimeToTicks(jet_event.event_start), 224 0, 225 jet_event.channel_num, 226 JET_EVENT_MARKER, 227 JET_MARKER_LOOP_END)) 228 self.tracks[jet_event.track_num].events.MergeEvents(events) 229 230 elif jet_event.event_type == JetDefs.E_APP: 231 if jet_event.track_num >= len(self.tracks): 232 raise JetFileException('Track number %d of out of range for app marker' % jet_event.track_num) 233 if jet_event.channel_num > 15: 234 raise JetFileException('Channel number %d of out of range for app marker' % jet_event.channel_num) 235 if jet_event.event_id > 83 or jet_event.event_id < 80: 236 raise JetFileException('EventID %d out of range for application controller' % jet_event.event_id) 237 238 events = midifile.EventList() 239 logging.debug('Adding application controller at %s' % jet_event.event_start) 240 events.append(midifile.ControlChangeEvent( 241 self.ConvertMusicTimeToTicks(jet_event.event_start), 242 0, 243 jet_event.channel_num, 244 jet_event.event_id, 245 jet_event.event_id)) 246 self.tracks[jet_event.track_num].events.MergeEvents(events) 247 248 class JetFile (object): 249 """Write a JET file based on a configuration file.""" 250 def __init__ (self, config_file, options): 251 self.config_file = config_file 252 self.config = config = ConfigParser.ConfigParser() 253 if self.config_file == "": 254 self.InitializeConfig(JetDefs.UNTITLED_FILE) 255 if not FileExists(self.config_file): 256 self.InitializeConfig(self.config_file) 257 258 config.read(self.config_file) 259 self.ParseConfig(options) 260 261 def DumpConfig (self): 262 """Drump configuration to log file.""" 263 # dump configuration 264 config = self.config 265 for section in config.sections(): 266 logging.debug('[%s]' % section) 267 for option, value in config.items(section): 268 logging.debug('%s: %s' % (option, value)) 269 270 def ParseConfig (self, options): 271 """Validate the configuration.""" 272 # check for output name 273 config = self.config 274 if config.has_option(OUTPUT_SECTION, OUTPUT_FILENAME): 275 config.filename = config.get(OUTPUT_SECTION, OUTPUT_FILENAME) 276 else: 277 raise JetFileException('No output filename in configuration file') 278 if config.filename == '' or config.filename == None: 279 config.filename = FileJustRoot(self.config_file) + ".JET" 280 config.chase_controllers = True 281 if config.has_option(OUTPUT_SECTION, OUTPUT_CHASE_CONTROLLERS): 282 try: 283 config.chase_controllers = config.getboolean(OUTPUT_SECTION, OUTPUT_CHASE_CONTROLLERS) 284 except: 285 pass 286 287 config.delete_empty_tracks = False 288 if config.has_option(OUTPUT_SECTION, OUTPUT_OMIT_EMPTY_TRACKS): 289 try: 290 config.delete_empty_tracks = config.getboolean(OUTPUT_SECTION, OUTPUT_OMIT_EMPTY_TRACKS) 291 except: 292 pass 293 294 config.copyright = None 295 if config.has_option(OUTPUT_SECTION, OUTPUT_COPYRIGHT): 296 config.copyright = config.get(OUTPUT_SECTION, OUTPUT_COPYRIGHT) 297 298 config.app_data = None 299 if config.has_option(OUTPUT_SECTION, OUTPUT_APP_DATA): 300 config.app_data = config.get(OUTPUT_SECTION, OUTPUT_APP_DATA) 301 302 # count segments 303 segments = [] 304 seg_num = 0 305 while 1: 306 307 # check for segment section 308 segment_name = SEGMENT_SECTION + str(seg_num) 309 if not config.has_section(segment_name): 310 break 311 312 # initialize some parameters 313 start = end = length = output = end_marker = dlsfile = dump_file = None 314 transpose = repeat = mute_flags = 0 315 jetevents = [] 316 317 # get the segment parameters 318 segname = config.get(segment_name, SEGMENT_NAME) 319 filename = config.get(segment_name, SEGMENT_FILENAME) 320 if config.has_option(segment_name, SEGMENT_DLSFILE): 321 dlsfile = config.get(segment_name, SEGMENT_DLSFILE) 322 if config.has_option(segment_name, SEGMENT_START): 323 start = config.get(segment_name, SEGMENT_START) 324 if config.has_option(segment_name, SEGMENT_END): 325 end = config.get(segment_name, SEGMENT_END) 326 if config.has_option(segment_name, SEGMENT_LENGTH): 327 length = config.get(segment_name, SEGMENT_LENGTH) 328 if config.has_option(segment_name, SEGMENT_OUTPUT): 329 output = config.get(segment_name, SEGMENT_OUTPUT) 330 if config.has_option(segment_name, SEGMENT_QUANTIZE): 331 quantize = config.get(segment_name, SEGMENT_QUANTIZE) 332 if config.has_option(segment_name, SEGMENT_DUMP_FILE): 333 dump_file = config.get(segment_name, SEGMENT_DUMP_FILE) 334 #API FIELDS 335 if config.has_option(segment_name, SEGMENT_TRANSPOSE): 336 transpose = config.get(segment_name, SEGMENT_TRANSPOSE) 337 if config.has_option(segment_name, SEGMENT_REPEAT): 338 repeat = config.get(segment_name, SEGMENT_REPEAT) 339 if config.has_option(segment_name, SEGMENT_MUTE_FLAGS): 340 mute_flags = config.get(segment_name, SEGMENT_MUTE_FLAGS) 341 342 if config.has_option(segment_name, SEGMENT_END_MARKER): 343 end_marker = config.get(segment_name, SEGMENT_END_MARKER) 344 track_num, channel_num, event_time = end_marker.split(',',2) 345 #jetevents.append((JetDefs.E_EOS, 0, int(track_num), int(channel_num), event_time, '')) 346 jetevents.append(JetEvent(JetDefs.E_EOS, JetDefs.E_EOS, 0, int(track_num), int(channel_num), event_time, event_time)) 347 348 # check for jetevents 349 for jetevent, location in config.items(segment_name): 350 if jetevent.startswith(CLIP_PREFIX): 351 event_name, event_id, track_num, channel_num, event_start, event_end = location.split(',', 5) 352 jetevents.append(JetEvent(event_name, JetDefs.E_CLIP, int(event_id), int(track_num), int(channel_num), event_start, event_end)) 353 354 # check for appevents 355 for jetevent, location in config.items(segment_name): 356 if jetevent.startswith(APP_PREFIX): 357 event_name, event_id, track_num, channel_num, event_start, event_end = location.split(',', 5) 358 jetevents.append(JetEvent(event_name, JetDefs.E_APP, int(event_id), int(track_num), int(channel_num), event_start, event_end)) 359 360 segments.append(JetSegment(segname, filename, start, end, length, output, quantize, jetevents, dlsfile, dump_file, int(transpose), int(repeat), int(mute_flags))) 361 seg_num += 1 362 363 self.segments = segments 364 if not len(segments): 365 #TODO: Check for segments when writing 366 #raise JetFileException('No segments defined in configuration file') 367 pass 368 369 # count libraries 370 libraries = [] 371 lib_num = 0 372 while 1: 373 library_name = LIBRARY_FILENAME + str(lib_num) 374 if not config.has_option(LIBRARY_SECTION, library_name): 375 break 376 libraries.append(config.get(LIBRARY_SECTION, library_name)) 377 lib_num += 1 378 self.libraries = libraries 379 380 def WriteJetFileFromConfig (self, options): 381 """Write JET file from config file.""" 382 383 # open the output file and write the header 384 output_file = open(self.config.filename, 'wb') 385 jet_header = struct.pack(JET_HEADER_STRUCT, JET_HEADER_TAG, 0) 386 output_file.write(jet_header) 387 388 # write the JINF chunk 389 jet_info = struct.pack(JINF_STRUCT, 390 JET_INFO_CHUNK, struct.calcsize(JINF_STRUCT) - 8, 391 JINF_JET_VERSION, JET_VERSION, 392 JINF_NUM_SMF_CHUNKS, len(self.segments), 393 JINF_NUM_DLS_CHUNKS, len(self.libraries)) 394 output_file.write(jet_info) 395 396 # write the JCOP chunk (if any) 397 if self.config.copyright is not None: 398 size = len(self.config.copyright) + 1 399 if size & 1: 400 size += 1 401 extra_byte = True 402 else: 403 extra_byte = False 404 jet_copyright = struct.pack(JCOP_STRUCT, JCOP_CHUNK, size) 405 output_file.write(jet_copyright) 406 output_file.write(self.config.copyright) 407 output_file.write(chr(0)) 408 if extra_byte: 409 output_file.write(chr(0)) 410 411 # write the app data chunk (if any) 412 if self.config.app_data is not None: 413 size = os.path.getsize(self.config.app_data) 414 if size & 1: 415 size += 1 416 extra_byte = True 417 else: 418 extra_byte = False 419 jet_app_data = struct.pack(JAPP_STRUCT, JAPP_CHUNK, size) 420 output_file.write(jet_app_data) 421 with open(self.config.app_data, 'rb') as f: 422 output_file.write(f.read()) 423 if extra_byte: 424 output_file.write(chr(0)) 425 426 # copy the MIDI segments 427 seg_num = 0 428 for segment in self.segments: 429 logging.debug('Writing segment %d' % seg_num) 430 431 # open SMF file and read it 432 jet_segfile = JetSegmentFile(segment.filename, 'rb') 433 jet_segfile.ReadFromStream() 434 435 # insert events 436 jet_segfile.AddJetEvents(segment.jetevents) 437 438 # trim to length specified in config file 439 jet_segfile.ExtractEvents(segment.start, segment.end, segment.length, segment.quantize, self.config.chase_controllers) 440 441 # chase controller events and fix them 442 if self.config.chase_controllers: 443 jet_segfile.SyncClips() 444 445 # delete empty tracks 446 if self.config.delete_empty_tracks: 447 jet_segfile.DeleteEmptyTracks() 448 449 # write separate output file if requested 450 if segment.output is not None: 451 jet_segfile.SaveAs(segment.output) 452 453 # write dump file 454 if segment.dump_file is not None: 455 with open(segment.dump_file, 'w') as f: 456 jet_segfile.DumpTracks(f) 457 458 # write the segment header 459 header_pos = output_file.tell() 460 smf_header = struct.pack(JET_HEADER_STRUCT, JET_SMF_CHUNK, 0) 461 output_file.write(smf_header) 462 start_pos = output_file.tell() 463 464 # write SMF file to output file 465 jet_segfile.Write(output_file, offset=start_pos) 466 jet_segfile.close() 467 468 # return to segment header and write actual size 469 end_pos = output_file.tell() 470 file_size = end_pos - start_pos 471 if file_size & 1: 472 file_size += 1 473 end_pos += 1 474 output_file.seek(header_pos, 0) 475 smf_header = struct.pack(JET_HEADER_STRUCT, JET_SMF_CHUNK, file_size) 476 output_file.write(smf_header) 477 output_file.seek(end_pos, 0) 478 479 seg_num += 1 480 481 # copy the DLS segments 482 for library in self.libraries: 483 if FileExists(library): 484 # open SMF file and get size 485 lib_file = (open(library,'rb')) 486 lib_file.seek(0,2) 487 file_size = lib_file.tell() 488 lib_file.seek(0) 489 490 # write the library header 491 dls_header = struct.pack(JET_HEADER_STRUCT, JET_DLS_CHUNK, file_size) 492 output_file.write(dls_header) 493 494 # copy DLS file to output file 495 output_file.write(lib_file.read()) 496 lib_file.close() 497 498 # write the header with the read data size 499 file_size = output_file.tell() 500 output_file.seek(0) 501 jet_header = struct.pack(JET_HEADER_STRUCT, JET_HEADER_TAG, file_size - struct.calcsize(JET_HEADER_STRUCT)) 502 output_file.write(jet_header) 503 output_file.close() 504 505 def GetMidiFiles(self): 506 """ Gets a list of midifiles """ 507 midiFiles = [] 508 for segment in self.segments: 509 if segment.filename not in midiFiles: 510 midiFiles.append(segment.filename) 511 return midiFiles 512 513 def GetLibraries(self): 514 """ Gets the libraries """ 515 return self.libraries 516 517 def GetEvents(self, segName): 518 """ Gets the events for a segment """ 519 for segment in self.segments: 520 if segment.segname == segName: 521 return segment.jetevents 522 return None 523 524 def GetEvent(self, segName, eventName): 525 """ Gets a single event from a segment """ 526 for segment in self.segments: 527 if segment.segname == segName: 528 for event in segment.jetevents: 529 if event.event_name == eventName: 530 return event 531 return None 532 533 def AddEvent(self, segname, event_name, event_type, event_id, track_num, channel_num, event_start, event_end): 534 """ Adds an event """ 535 for segment in self.segments: 536 if segment.segname == segname: 537 segment.jetevents.append(JetEvent(event_name, event_type, int(event_id), int(track_num), int(channel_num), event_start, event_end)) 538 539 def ReplaceEvents(self, segname, newEvents): 540 """ Replaces all events """ 541 for segment in self.segments: 542 if segment.segname == segname: 543 segment.jetevents = newEvents 544 return segment 545 546 def UpdateEvent(self, segname, orgeventname, event_name, event_type, event_id, track_num, channel_num, event_start, event_end): 547 """ Updates an event """ 548 for segment in self.segments: 549 if segment.segname == segname: 550 for jetevent in segment.jetevents: 551 if jetevent.event_name == orgeventname: 552 jetevent.event_name = event_name 553 jetevent.event_type = event_type 554 jetevent.event_id = event_id 555 jetevent.track_num = track_num 556 jetevent.channel_num = channel_num 557 jetevent.event_start = event_start 558 jetevent.event_end = event_end 559 560 def DeleteSegmentsMatchingPrefix(self, prefix): 561 """ Deletes all segments matching name """ 562 iOnce = True 563 iAgain = False 564 while(iOnce or iAgain): 565 iOnce = False 566 iAgain = False 567 for segment in self.segments: 568 if segment.segname[0:len(prefix)].upper() == prefix.upper(): 569 self.segments.remove(segment) 570 iAgain = True 571 572 def DeleteEvent(self, segname, event_name): 573 """ Deletes an event """ 574 for segment in self.segments: 575 if segment.segname == segname: 576 for jetevent in segment.jetevents: 577 if jetevent.event_name == event_name: 578 segment.jetevents.remove(jetevent) 579 580 def DeleteEventsMatchingPrefix(self, segname, prefix): 581 """ Deletes all events matching name """ 582 for segment in self.segments: 583 if segment.segname == segname: 584 iOnce = True 585 iAgain = False 586 while(iOnce or iAgain): 587 iOnce = False 588 iAgain = False 589 for jetevent in segment.jetevents: 590 if jetevent.event_name[0:len(prefix)].upper() == prefix.upper(): 591 segment.jetevents.remove(jetevent) 592 iAgain = True 593 594 def MoveEvent(self, segname, movename, event_start, event_end): 595 """ Move an event """ 596 for segment in self.segments: 597 if segment.segname == segname: 598 for jetevent in segment.jetevents: 599 if jetevent.event_name == movename: 600 jetevent.event_start = event_start 601 jetevent.event_end = event_end 602 return 603 604 def GetSegments(self): 605 """ Gets all segments """ 606 return self.segments 607 608 def GetSegment(self, segName): 609 """ Gets one segment by name """ 610 for segment in self.segments: 611 if segment.segname == segName: 612 return segment 613 return None 614 615 def AddSegment(self, segname, filename, start, end, length, output, quantize, jetevents, dlsfile, dump_file, transpose, repeat, mute_flags): 616 """ Adds a segment """ 617 if length == JetDefs.MBT_ZEROSTR: 618 length = None 619 if end == JetDefs.MBT_ZEROSTR: 620 end = None 621 self.segments.append(JetSegment(segname, filename, start, end, length, output, quantize, jetevents, dlsfile, dump_file, transpose, repeat, mute_flags)) 622 623 def UpdateSegment(self, orgsegname, segname, filename, start, end, length, output, quantize, jetevents, dlsfile, dump_file, transpose, repeat, mute_flags): 624 """ Updates a segment """ 625 if length == JetDefs.MBT_ZEROSTR: 626 length = None 627 if end == JetDefs.MBT_ZEROSTR: 628 end = None 629 for segment in self.segments: 630 if segment.segname == orgsegname: 631 segment.segname = segname 632 segment.filename = filename 633 segment.start = start 634 segment.end = end 635 segment.length = length 636 segment.output = output 637 segment.quantize = quantize 638 segment.dlsfile = dlsfile 639 segment.transpose = transpose 640 segment.repeat = repeat 641 segment.mute_flags = mute_flags 642 643 def MoveSegment(self, segname, start, end): 644 """ Moves a segment """ 645 for segment in self.segments: 646 if segment.segname == segname: 647 segment.start = start 648 segment.end = end 649 return 650 651 def DeleteSegment(self, segname): 652 """ Deletes a segment """ 653 for segment in self.segments: 654 if segment.segname == segname: 655 self.segments.remove(segment) 656 657 def SaveJetConfig(self, configFile): 658 """ Saves the jet config file """ 659 if self.config.filename == '' or self.config.filename == None: 660 self.config.filename = FileJustRoot(configFile) + ".JET" 661 config = ConfigParser.ConfigParser() 662 config.add_section(OUTPUT_SECTION) 663 config.set(OUTPUT_SECTION, OUTPUT_FILENAME, self.config.filename) 664 config.set(OUTPUT_SECTION, OUTPUT_CHASE_CONTROLLERS, self.config.chase_controllers) 665 config.set(OUTPUT_SECTION, OUTPUT_OMIT_EMPTY_TRACKS, self.config.delete_empty_tracks) 666 if self.config.copyright is not None: 667 config.set(OUTPUT_SECTION, OUTPUT_COPYRIGHT, self.config.copyright) 668 if self.config.app_data is not None: 669 config.set(OUTPUT_SECTION, OUTPUT_APP_DATA, self.config.app_data) 670 671 self.libraries = [] 672 seg_num = 0 673 for segment in self.segments: 674 segment_name = SEGMENT_SECTION + str(seg_num) 675 config.add_section(segment_name) 676 config.set(segment_name, SEGMENT_NAME, segment.segname) 677 config.set(segment_name, SEGMENT_FILENAME, segment.filename) 678 679 config.set(segment_name, SEGMENT_DLSFILE, segment.dlsfile) 680 if FileExists(segment.dlsfile): 681 if not segment.dlsfile in self.libraries: 682 self.libraries.append(segment.dlsfile) 683 config.set(segment_name, SEGMENT_START, segment.start) 684 if segment.end > JetDefs.MBT_ZEROSTR and len(segment.end) > 0: 685 config.set(segment_name, SEGMENT_END, segment.end) 686 if segment.length > JetDefs.MBT_ZEROSTR and len(segment.length) > 0: 687 config.set(segment_name, SEGMENT_LENGTH, segment.length) 688 config.set(segment_name, SEGMENT_OUTPUT, segment.output) 689 config.set(segment_name, SEGMENT_QUANTIZE, segment.quantize) 690 if segment.dump_file is not None: 691 config.set(segment_name, SEGMENT_DUMP_FILE, segment.dump_file) 692 config.set(segment_name, SEGMENT_TRANSPOSE, segment.transpose) 693 config.set(segment_name, SEGMENT_REPEAT, segment.repeat) 694 config.set(segment_name, SEGMENT_MUTE_FLAGS, segment.mute_flags) 695 696 clip_num = 0 697 app_num = 0 698 for jet_event in segment.jetevents: 699 if jet_event.event_type == JetDefs.E_CLIP: 700 clip_name = CLIP_PREFIX + str(clip_num) 701 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) 702 config.set(segment_name, clip_name, s) 703 clip_num += 1 704 elif jet_event.event_type == JetDefs.E_APP: 705 app_name = APP_PREFIX + str(app_num) 706 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) 707 config.set(segment_name, app_name, s) 708 app_num += 1 709 elif jet_event.event_type == JetDefs.E_EOS: 710 s = "%s,%s,%s" % (jet_event.track_num, jet_event.channel_num, jet_event.event_start) 711 config.set(segment_name, SEGMENT_END_MARKER, s) 712 713 seg_num += 1 714 715 lib_num = 0 716 config.add_section(LIBRARY_SECTION) 717 for library in self.libraries: 718 library_name = LIBRARY_FILENAME + str(lib_num) 719 config.set(LIBRARY_SECTION, library_name, library) 720 lib_num += 1 721 722 FileKillClean(configFile) 723 cfgfile = open(configFile,'w') 724 config.write(cfgfile) 725 cfgfile.close() 726 727 def InitializeConfig(self, configFile): 728 """ Initializes the values for an empty flag """ 729 self.config.filename = FileJustRoot(configFile) + ".JET" 730 self.config.chase_controllers = True 731 self.config.delete_empty_tracks = False 732 self.config.copyright = None 733 self.config.app_data = None 734 self.segments = [] 735 self.libraries = [] 736 self.config_file = configFile 737 self.SaveJetConfig(configFile) 738 739 740 741 #--------------------------------------------------------------- 742 # main 743 #--------------------------------------------------------------- 744 if __name__ == '__main__': 745 sys = __import__('sys') 746 optparse = __import__('optparse') 747 748 # parse command line options 749 parser = optparse.OptionParser(version=VERSION) 750 parser.set_defaults(log_level=logging.INFO, log_file=None) 751 parser.add_option('-d', '--debug', action="store_const", const=logging.DEBUG, dest='log_level', help='Enable debug output') 752 parser.add_option('-l', '--log_file', dest='log_file', help='Write debug output to log file') 753 (options, args) = parser.parse_args() 754 755 # get master logger 756 logger = logging.getLogger('') 757 logger.setLevel(options.log_level) 758 759 # create console logger 760 console_logger = logging.StreamHandler() 761 console_logger.setFormatter(logging.Formatter('%(message)s')) 762 logger.addHandler(console_logger) 763 764 # create rotating file logger 765 if options.log_file is not None: 766 file_logger = logging.FileHandler(options.log_file, 'w') 767 file_logger.setFormatter(logging.Formatter('%(message)s')) 768 logger.addHandler(file_logger) 769 770 # process files 771 for arg in args: 772 print arg 773 jet_file = JetFile(arg, options) 774 jet_file.WriteJetFileFromConfig(options) 775 776